394eca19da41c2e536dc5cc49353a7b51216165a
[openwrt/staging/thess.git] /
1 From 9a89cb300c1ed5b90bae5684c88c85895a15c849 Mon Sep 17 00:00:00 2001
2 From: George Moussalem <george.moussalem@outlook.com>
3 Date: Mon, 02 Jun 2025 12:50:39 +0400
4 Subject: [PATCH v3 3/5] net: phy: qcom: at803x: Add Qualcomm IPQ5018 Internal PHY support
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset="utf-8"
7 Content-Transfer-Encoding: 7bit
8 Message-Id: <20250602-ipq5018-ge-phy-v3-3-0d8f39f402a6@outlook.com>
9
10 The IPQ5018 SoC contains a single internal Gigabit Ethernet PHY which
11 provides an MDI interface directly to an RJ45 connector or an external
12 switch over a PHY to PHY link.
13
14 The PHY supports 10/100/1000 mbps link modes, CDT, auto-negotiation and
15 802.3az EEE.
16
17 Let's add support for this PHY in the at803x driver as it falls within
18 the Qualcomm Atheros OUI.
19
20 Signed-off-by: George Moussalem <george.moussalem@outlook.com>
21 ---
22 drivers/net/phy/qcom/Kconfig | 2 +-
23 drivers/net/phy/qcom/at803x.c | 185 ++++++++++++++++++++++++++++++++++++++++--
24 2 files changed, 178 insertions(+), 9 deletions(-)
25
26 --- a/drivers/net/phy/qcom/Kconfig
27 +++ b/drivers/net/phy/qcom/Kconfig
28 @@ -7,7 +7,7 @@ config AT803X_PHY
29 select QCOM_NET_PHYLIB
30 depends on REGULATOR
31 help
32 - Currently supports the AR8030, AR8031, AR8033, AR8035 model
33 + Currently supports the AR8030, AR8031, AR8033, AR8035, IPQ5018 model
34
35 config QCA83XX_PHY
36 tristate "Qualcomm Atheros QCA833x PHYs"
37 --- a/drivers/net/phy/qcom/at803x.c
38 +++ b/drivers/net/phy/qcom/at803x.c
39 @@ -7,19 +7,24 @@
40 * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
41 */
42
43 -#include <linux/phy.h>
44 -#include <linux/module.h>
45 -#include <linux/string.h>
46 -#include <linux/netdevice.h>
47 +#include <linux/bitfield.h>
48 +#include <linux/clk.h>
49 +#include <linux/clk-provider.h>
50 #include <linux/etherdevice.h>
51 #include <linux/ethtool_netlink.h>
52 -#include <linux/bitfield.h>
53 -#include <linux/regulator/of_regulator.h>
54 -#include <linux/regulator/driver.h>
55 -#include <linux/regulator/consumer.h>
56 +#include <linux/mfd/syscon.h>
57 +#include <linux/module.h>
58 +#include <linux/netdevice.h>
59 #include <linux/of.h>
60 +#include <linux/phy.h>
61 #include <linux/phylink.h>
62 +#include <linux/regmap.h>
63 +#include <linux/regulator/consumer.h>
64 +#include <linux/regulator/driver.h>
65 +#include <linux/regulator/of_regulator.h>
66 +#include <linux/reset.h>
67 #include <linux/sfp.h>
68 +#include <linux/string.h>
69 #include <dt-bindings/net/qca-ar803x.h>
70
71 #include "qcom.h"
72 @@ -93,6 +98,8 @@
73 #define ATH8035_PHY_ID 0x004dd072
74 #define AT8030_PHY_ID_MASK 0xffffffef
75
76 +#define IPQ5018_PHY_ID 0x004dd0c0
77 +
78 #define QCA9561_PHY_ID 0x004dd042
79
80 #define AT803X_PAGE_FIBER 0
81 @@ -105,6 +112,50 @@
82 /* disable hibernation mode */
83 #define AT803X_DISABLE_HIBERNATION_MODE BIT(2)
84
85 +#define IPQ5018_PHY_FIFO_CONTROL 0x19
86 +#define IPQ5018_PHY_FIFO_RESET GENMASK(1, 0)
87 +
88 +#define IPQ5018_PHY_DEBUG_EDAC 0x4380
89 +#define IPQ5018_PHY_MMD1_MDAC 0x8100
90 +#define IPQ5018_PHY_DAC_MASK GENMASK(15, 8)
91 +
92 +/* MDAC and EDAC values for short cable length */
93 +#define IPQ5018_PHY_DEBUG_EDAC_VAL 0x10
94 +#define IPQ5018_PHY_MMD1_MDAC_VAL 0x10
95 +
96 +#define IPQ5018_PHY_MMD1_MSE_THRESH1 0x1000
97 +#define IPQ5018_PHY_MMD1_MSE_THRESH2 0x1001
98 +#define IPQ5018_PHY_PCS_AZ_CTRL1 0x8008
99 +#define IPQ5018_PHY_PCS_AZ_CTRL2 0x8009
100 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL3 0x8074
101 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL4 0x8075
102 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL5 0x8076
103 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL6 0x8077
104 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL7 0x8078
105 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL9 0x807a
106 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL13 0x807e
107 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL14 0x807f
108 +
109 +#define IPQ5018_PHY_MMD1_MSE_THRESH1_VAL 0xf1
110 +#define IPQ5018_PHY_MMD1_MSE_THRESH2_VAL 0x1f6
111 +#define IPQ5018_PHY_PCS_AZ_CTRL1_VAL 0x7880
112 +#define IPQ5018_PHY_PCS_AZ_CTRL2_VAL 0xc8
113 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL3_VAL 0xc040
114 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL4_VAL 0xa060
115 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL5_VAL 0xc040
116 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL6_VAL 0xa060
117 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL7_VAL 0xc24c
118 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL9_VAL 0xc060
119 +#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL13_VAL 0xb060
120 +#define IPQ5018_PHY_PCS_NEAR_ECHO_THRESH_VAL 0x90b0
121 +
122 +#define IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE 0x1
123 +#define IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_MASK GENMASK(7, 4)
124 +#define IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_DEFAULT 0x50
125 +#define IPQ5018_PHY_DEBUG_ANA_DAC_FILTER 0xa080
126 +
127 +#define IPQ5018_TCSR_ETH_LDO_READY BIT(0)
128 +
129 MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
130 MODULE_AUTHOR("Matus Ujhelyi");
131 MODULE_LICENSE("GPL");
132 @@ -130,6 +181,11 @@ struct at803x_context {
133 u16 led_control;
134 };
135
136 +struct ipq5018_priv {
137 + struct reset_control *rst;
138 + bool set_short_cable_dac;
139 +};
140 +
141 static int at803x_write_page(struct phy_device *phydev, int page)
142 {
143 int mask;
144 @@ -960,6 +1016,105 @@ static int at8035_probe(struct phy_devic
145 return at8035_parse_dt(phydev);
146 }
147
148 +static int ipq5018_cable_test_start(struct phy_device *phydev)
149 +{
150 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL3,
151 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL3_VAL);
152 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL4,
153 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL4_VAL);
154 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL5,
155 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL5_VAL);
156 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL6,
157 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL6_VAL);
158 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL7,
159 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL7_VAL);
160 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL9,
161 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL9_VAL);
162 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL13,
163 + IPQ5018_PHY_PCS_CDT_THRESH_CTRL13_VAL);
164 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL3,
165 + IPQ5018_PHY_PCS_NEAR_ECHO_THRESH_VAL);
166 +
167 + /* we do all the (time consuming) work later */
168 + return 0;
169 +}
170 +
171 +static int ipq5018_config_init(struct phy_device *phydev)
172 +{
173 + struct ipq5018_priv *priv = phydev->priv;
174 + u16 val = 0;
175 +
176 + /*
177 + * set LDO efuse: first temporarily store ANA_DAC_FILTER value from
178 + * debug register as it will be reset once the ANA_LDO_EFUSE register
179 + * is written to
180 + */
181 + val = at803x_debug_reg_read(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER);
182 + at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE,
183 + IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_MASK,
184 + IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_DEFAULT);
185 + at803x_debug_reg_write(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER, val);
186 +
187 + /* set 8023AZ CTRL values */
188 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_AZ_CTRL1,
189 + IPQ5018_PHY_PCS_AZ_CTRL1_VAL);
190 + phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_AZ_CTRL2,
191 + IPQ5018_PHY_PCS_AZ_CTRL2_VAL);
192 +
193 + /* set MSE threshold values */
194 + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MSE_THRESH1,
195 + IPQ5018_PHY_MMD1_MSE_THRESH1_VAL);
196 + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MSE_THRESH2,
197 + IPQ5018_PHY_MMD1_MSE_THRESH2_VAL);
198 +
199 + /* PHY DAC values are optional and only set in a PHY to PHY link architecture */
200 + if (priv->set_short_cable_dac) {
201 + /* setting MDAC (Multi-level Digital-to-Analog Converter) in MMD1 */
202 + phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC,
203 + IPQ5018_PHY_DAC_MASK, IPQ5018_PHY_MMD1_MDAC_VAL);
204 +
205 + /* setting EDAC (Error-detection and Correction) in debug register */
206 + at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC,
207 + IPQ5018_PHY_DAC_MASK, IPQ5018_PHY_DEBUG_EDAC_VAL);
208 + }
209 +
210 + return 0;
211 +}
212 +
213 +static void ipq5018_link_change_notify(struct phy_device *phydev)
214 +{
215 + mdiobus_modify_changed(phydev->mdio.bus, phydev->mdio.addr,
216 + IPQ5018_PHY_FIFO_CONTROL, IPQ5018_PHY_FIFO_RESET,
217 + phydev->link ? IPQ5018_PHY_FIFO_RESET : 0);
218 +}
219 +
220 +static int ipq5018_probe(struct phy_device *phydev)
221 +{
222 + struct device *dev = &phydev->mdio.dev;
223 + struct ipq5018_priv *priv;
224 + int ret;
225 +
226 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
227 + if (!priv)
228 + return -ENOMEM;
229 +
230 + priv->set_short_cable_dac = of_property_read_bool(dev->of_node,
231 + "qcom,dac-preset-short-cable");
232 +
233 + priv->rst = devm_reset_control_array_get_exclusive(dev);
234 + if (IS_ERR_OR_NULL(priv->rst))
235 + return dev_err_probe(dev, PTR_ERR(priv->rst),
236 + "failed to acquire reset\n");
237 +
238 + ret = reset_control_reset(priv->rst);
239 + if (ret)
240 + return dev_err_probe(dev, ret, "failed to reset\n");
241 +
242 + phydev->priv = priv;
243 +
244 + return 0;
245 +}
246 +
247 static struct phy_driver at803x_driver[] = {
248 {
249 /* Qualcomm Atheros AR8035 */
250 @@ -1052,6 +1207,19 @@ static struct phy_driver at803x_driver[]
251 .soft_reset = genphy_soft_reset,
252 .config_aneg = at803x_config_aneg,
253 }, {
254 + PHY_ID_MATCH_EXACT(IPQ5018_PHY_ID),
255 + .name = "Qualcomm Atheros IPQ5018 internal PHY",
256 + .flags = PHY_IS_INTERNAL | PHY_POLL_CABLE_TEST,
257 + .probe = ipq5018_probe,
258 + .config_init = ipq5018_config_init,
259 + .link_change_notify = ipq5018_link_change_notify,
260 + .read_status = at803x_read_status,
261 + .config_intr = at803x_config_intr,
262 + .handle_interrupt = at803x_handle_interrupt,
263 + .cable_test_start = ipq5018_cable_test_start,
264 + .cable_test_get_status = qca808x_cable_test_get_status,
265 + .soft_reset = genphy_soft_reset,
266 +}, {
267 /* Qualcomm Atheros QCA9561 */
268 PHY_ID_MATCH_EXACT(QCA9561_PHY_ID),
269 .name = "Qualcomm Atheros QCA9561 built-in PHY",
270 @@ -1077,6 +1245,7 @@ static const struct mdio_device_id __may
271 { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
272 { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
273 { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
274 + { PHY_ID_MATCH_EXACT(IPQ5018_PHY_ID) },
275 { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
276 { }
277 };