ipq40xx: qca807x: add suspend and resume ops
[openwrt/staging/jow.git] / target / linux / ipq40xx / files / drivers / net / phy / qca807x.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2020 Sartura Ltd.
4 *
5 * Author: Robert Marko <robert.marko@sartura.hr>
6 *
7 * Qualcomm QCA8072 and QCA8075 PHY driver
8 */
9
10 #include <linux/version.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/phy.h>
14 #include <linux/bitfield.h>
15 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
16 #include <linux/ethtool_netlink.h>
17 #endif
18 #include <linux/gpio.h>
19 #include <linux/sfp.h>
20
21 #include <dt-bindings/net/qcom-qca807x.h>
22
23 #define PHY_ID_QCA8072 0x004dd0b2
24 #define PHY_ID_QCA8075 0x004dd0b1
25 #define PHY_ID_QCA807X_PSGMII 0x06820805
26
27 /* Downshift */
28 #define QCA807X_SMARTSPEED_EN BIT(5)
29 #define QCA807X_SMARTSPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
30 #define QCA807X_SMARTSPEED_RETRY_LIMIT_DEFAULT 5
31 #define QCA807X_SMARTSPEED_RETRY_LIMIT_MIN 2
32 #define QCA807X_SMARTSPEED_RETRY_LIMIT_MAX 9
33
34 /* Cable diagnostic test (CDT) */
35 #define QCA807X_CDT 0x16
36 #define QCA807X_CDT_ENABLE BIT(15)
37 #define QCA807X_CDT_ENABLE_INTER_PAIR_SHORT BIT(13)
38 #define QCA807X_CDT_STATUS BIT(11)
39 #define QCA807X_CDT_MMD3_STATUS 0x8064
40 #define QCA807X_CDT_MDI0_STATUS_MASK GENMASK(15, 12)
41 #define QCA807X_CDT_MDI1_STATUS_MASK GENMASK(11, 8)
42 #define QCA807X_CDT_MDI2_STATUS_MASK GENMASK(7, 4)
43 #define QCA807X_CDT_MDI3_STATUS_MASK GENMASK(3, 0)
44 #define QCA807X_CDT_RESULTS_INVALID 0x0
45 #define QCA807X_CDT_RESULTS_OK 0x1
46 #define QCA807X_CDT_RESULTS_OPEN 0x2
47 #define QCA807X_CDT_RESULTS_SAME_SHORT 0x3
48 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK 0x4
49 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK 0x8
50 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK 0xc
51 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN 0x6
52 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN 0xa
53 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN 0xe
54 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT 0x7
55 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT 0xb
56 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT 0xf
57 #define QCA807X_CDT_RESULTS_BUSY 0x9
58 #define QCA807X_CDT_MMD3_MDI0_LENGTH 0x8065
59 #define QCA807X_CDT_MMD3_MDI1_LENGTH 0x8066
60 #define QCA807X_CDT_MMD3_MDI2_LENGTH 0x8067
61 #define QCA807X_CDT_MMD3_MDI3_LENGTH 0x8068
62 #define QCA807X_CDT_SAME_SHORT_LENGTH_MASK GENMASK(15, 8)
63 #define QCA807X_CDT_CROSS_SHORT_LENGTH_MASK GENMASK(7, 0)
64
65 #define QCA807X_CHIP_CONFIGURATION 0x1f
66 #define QCA807X_BT_BX_REG_SEL BIT(15)
67 #define QCA807X_BT_BX_REG_SEL_FIBER 0
68 #define QCA807X_BT_BX_REG_SEL_COPPER 1
69 #define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0)
70 #define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4
71 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3
72 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0
73
74 #define QCA807X_MEDIA_SELECT_STATUS 0x1a
75 #define QCA807X_MEDIA_DETECTED_COPPER BIT(5)
76 #define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4)
77 #define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3)
78
79 #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e
80 #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0)
81
82 #define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a
83 #define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0)
84
85 #define QCA807X_MMD7_LED_100N_1 0x8074
86 #define QCA807X_MMD7_LED_100N_2 0x8075
87 #define QCA807X_MMD7_LED_1000N_1 0x8076
88 #define QCA807X_MMD7_LED_1000N_2 0x8077
89 #define QCA807X_LED_TXACT_BLK_EN_2 BIT(10)
90 #define QCA807X_LED_RXACT_BLK_EN_2 BIT(9)
91 #define QCA807X_LED_GT_ON_EN_2 BIT(6)
92 #define QCA807X_LED_HT_ON_EN_2 BIT(5)
93 #define QCA807X_LED_BT_ON_EN_2 BIT(4)
94 #define QCA807X_GPIO_FORCE_EN BIT(15)
95 #define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
96
97 #define QCA807X_INTR_ENABLE 0x12
98 #define QCA807X_INTR_STATUS 0x13
99 #define QCA807X_INTR_ENABLE_AUTONEG_ERR BIT(15)
100 #define QCA807X_INTR_ENABLE_SPEED_CHANGED BIT(14)
101 #define QCA807X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
102 #define QCA807X_INTR_ENABLE_LINK_FAIL BIT(11)
103 #define QCA807X_INTR_ENABLE_LINK_SUCCESS BIT(10)
104
105 #define QCA807X_FUNCTION_CONTROL 0x10
106 #define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
107 #define QCA807X_FC_MDI_CROSSOVER_AUTO 3
108 #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1
109 #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0
110
111 #define QCA807X_PHY_SPECIFIC_STATUS 0x11
112 #define QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED BIT(11)
113 #define QCA807X_SS_SPEED_MASK GENMASK(15, 14)
114 #define QCA807X_SS_SPEED_1000 2
115 #define QCA807X_SS_SPEED_100 1
116 #define QCA807X_SS_SPEED_10 0
117 #define QCA807X_SS_DUPLEX BIT(13)
118 #define QCA807X_SS_MDIX BIT(6)
119
120 /* PSGMII PHY specific */
121 #define PSGMII_QSGMII_DRIVE_CONTROL_1 0xb
122 #define PSGMII_QSGMII_TX_DRIVER_MASK GENMASK(7, 4)
123 #define PSGMII_MODE_CTRL 0x6d
124 #define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0)
125 #define PSGMII_MMD3_SERDES_CONTROL 0x805a
126
127 struct qca807x_gpio_priv {
128 struct phy_device *phy;
129 };
130
131 static int qca807x_get_downshift(struct phy_device *phydev, u8 *data)
132 {
133 int val, cnt, enable;
134
135 val = phy_read(phydev, MII_NWAYTEST);
136 if (val < 0)
137 return val;
138
139 enable = FIELD_GET(QCA807X_SMARTSPEED_EN, val);
140 cnt = FIELD_GET(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, val) + 2;
141
142 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
143
144 return 0;
145 }
146
147 static int qca807x_set_downshift(struct phy_device *phydev, u8 cnt)
148 {
149 int ret, val;
150
151 if (cnt > QCA807X_SMARTSPEED_RETRY_LIMIT_MAX ||
152 (cnt < QCA807X_SMARTSPEED_RETRY_LIMIT_MIN && cnt != DOWNSHIFT_DEV_DISABLE))
153 return -EINVAL;
154
155 if (!cnt) {
156 ret = phy_clear_bits(phydev, MII_NWAYTEST, QCA807X_SMARTSPEED_EN);
157 } else {
158 val = QCA807X_SMARTSPEED_EN;
159 val |= FIELD_PREP(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, cnt - 2);
160
161 phy_modify(phydev, MII_NWAYTEST,
162 QCA807X_SMARTSPEED_EN |
163 QCA807X_SMARTSPEED_RETRY_LIMIT_MASK,
164 val);
165 }
166
167 ret = genphy_soft_reset(phydev);
168
169 return ret;
170 }
171
172 static int qca807x_get_tunable(struct phy_device *phydev,
173 struct ethtool_tunable *tuna, void *data)
174 {
175 switch (tuna->id) {
176 case ETHTOOL_PHY_DOWNSHIFT:
177 return qca807x_get_downshift(phydev, data);
178 default:
179 return -EOPNOTSUPP;
180 }
181 }
182
183 static int qca807x_set_tunable(struct phy_device *phydev,
184 struct ethtool_tunable *tuna, const void *data)
185 {
186 switch (tuna->id) {
187 case ETHTOOL_PHY_DOWNSHIFT:
188 return qca807x_set_downshift(phydev, *(const u8 *)data);
189 default:
190 return -EOPNOTSUPP;
191 }
192 }
193
194 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
195 static bool qca807x_distance_valid(int result)
196 {
197 switch (result) {
198 case QCA807X_CDT_RESULTS_OPEN:
199 case QCA807X_CDT_RESULTS_SAME_SHORT:
200 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK:
201 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK:
202 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK:
203 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
204 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
205 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
206 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
207 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
208 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
209 return true;
210 }
211 return false;
212 }
213
214 static int qca807x_report_length(struct phy_device *phydev,
215 int pair, int result)
216 {
217 int length;
218 int ret;
219
220 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA807X_CDT_MMD3_MDI0_LENGTH + pair);
221 if (ret < 0)
222 return ret;
223
224 switch (result) {
225 case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT:
226 length = (FIELD_GET(QCA807X_CDT_SAME_SHORT_LENGTH_MASK, ret) * 800) / 10;
227 break;
228 case ETHTOOL_A_CABLE_RESULT_CODE_OPEN:
229 case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT:
230 length = (FIELD_GET(QCA807X_CDT_CROSS_SHORT_LENGTH_MASK, ret) * 800) / 10;
231 break;
232 }
233
234 ethnl_cable_test_fault_length(phydev, pair, length);
235
236 return 0;
237 }
238
239 static int qca807x_cable_test_report_trans(int result)
240 {
241 switch (result) {
242 case QCA807X_CDT_RESULTS_OK:
243 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
244 case QCA807X_CDT_RESULTS_OPEN:
245 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
246 case QCA807X_CDT_RESULTS_SAME_SHORT:
247 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
248 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK:
249 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK:
250 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK:
251 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
252 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
253 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
254 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
255 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
256 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
257 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
258 default:
259 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
260 }
261 }
262
263 static int qca807x_cable_test_report(struct phy_device *phydev)
264 {
265 int pair0, pair1, pair2, pair3;
266 int ret;
267
268 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA807X_CDT_MMD3_STATUS);
269 if (ret < 0)
270 return ret;
271
272 pair0 = FIELD_GET(QCA807X_CDT_MDI0_STATUS_MASK, ret);
273 pair1 = FIELD_GET(QCA807X_CDT_MDI1_STATUS_MASK, ret);
274 pair2 = FIELD_GET(QCA807X_CDT_MDI2_STATUS_MASK, ret);
275 pair3 = FIELD_GET(QCA807X_CDT_MDI3_STATUS_MASK, ret);
276
277 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
278 qca807x_cable_test_report_trans(pair0));
279 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
280 qca807x_cable_test_report_trans(pair1));
281 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
282 qca807x_cable_test_report_trans(pair2));
283 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
284 qca807x_cable_test_report_trans(pair3));
285
286 if (qca807x_distance_valid(pair0))
287 qca807x_report_length(phydev, 0, qca807x_cable_test_report_trans(pair0));
288 if (qca807x_distance_valid(pair1))
289 qca807x_report_length(phydev, 1, qca807x_cable_test_report_trans(pair1));
290 if (qca807x_distance_valid(pair2))
291 qca807x_report_length(phydev, 2, qca807x_cable_test_report_trans(pair2));
292 if (qca807x_distance_valid(pair3))
293 qca807x_report_length(phydev, 3, qca807x_cable_test_report_trans(pair3));
294
295 return 0;
296 }
297
298 static int qca807x_cable_test_get_status(struct phy_device *phydev,
299 bool *finished)
300 {
301 int val;
302
303 *finished = false;
304
305 val = phy_read(phydev, QCA807X_CDT);
306 if (!((val & QCA807X_CDT_ENABLE) && (val & QCA807X_CDT_STATUS))) {
307 *finished = true;
308
309 return qca807x_cable_test_report(phydev);
310 }
311
312 return 0;
313 }
314
315 static int qca807x_cable_test_start(struct phy_device *phydev)
316 {
317 int val, ret;
318
319 val = phy_read(phydev, QCA807X_CDT);
320 /* Enable inter-pair short check as well */
321 val &= ~QCA807X_CDT_ENABLE_INTER_PAIR_SHORT;
322 val |= QCA807X_CDT_ENABLE;
323 ret = phy_write(phydev, QCA807X_CDT, val);
324
325 return ret;
326 }
327 #endif
328
329 #ifdef CONFIG_GPIOLIB
330 static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
331 {
332 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
333 return GPIO_LINE_DIRECTION_OUT;
334 #else
335 return GPIOF_DIR_OUT;
336 #endif
337 }
338
339 static int qca807x_gpio_get_reg(unsigned int offset)
340 {
341 return QCA807X_MMD7_LED_100N_2 + (offset % 2) * 2;
342 }
343
344 static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset)
345 {
346 struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
347 int val;
348
349 val = phy_read_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset));
350
351 return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
352 }
353
354 static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
355 {
356 struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
357 int val;
358
359 val = phy_read_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset));
360 val &= ~QCA807X_GPIO_FORCE_MODE_MASK;
361 val |= QCA807X_GPIO_FORCE_EN;
362 val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value);
363
364 phy_write_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset), val);
365 }
366
367 static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value)
368 {
369 qca807x_gpio_set(gc, offset, value);
370
371 return 0;
372 }
373
374 static int qca807x_gpio(struct phy_device *phydev)
375 {
376 struct device *dev = &phydev->mdio.dev;
377 struct qca807x_gpio_priv *priv;
378 struct gpio_chip *gc;
379
380 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
381 if (!priv)
382 return -ENOMEM;
383
384 priv->phy = phydev;
385
386 gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
387 if (!gc)
388 return -ENOMEM;
389
390 gc->label = dev_name(dev);
391 gc->base = -1;
392 gc->ngpio = 2;
393 gc->parent = dev;
394 gc->owner = THIS_MODULE;
395 gc->can_sleep = true;
396 gc->get_direction = qca807x_gpio_get_direction;
397 gc->direction_output = qca807x_gpio_dir_out;
398 gc->get = qca807x_gpio_get;
399 gc->set = qca807x_gpio_set;
400
401 return devm_gpiochip_add_data(dev, gc, priv);
402 }
403 #endif
404
405 static int qca807x_read_copper_status(struct phy_device *phydev)
406 {
407 int ss, err, old_link = phydev->link;
408
409 /* Update the link, but return if there was an error */
410 err = genphy_update_link(phydev);
411 if (err)
412 return err;
413
414 /* why bother the PHY if nothing can have changed */
415 if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
416 return 0;
417
418 phydev->speed = SPEED_UNKNOWN;
419 phydev->duplex = DUPLEX_UNKNOWN;
420 phydev->pause = 0;
421 phydev->asym_pause = 0;
422
423 err = genphy_read_lpa(phydev);
424 if (err < 0)
425 return err;
426
427 /* Read the QCA807x PHY-Specific Status register copper page,
428 * which indicates the speed and duplex that the PHY is actually
429 * using, irrespective of whether we are in autoneg mode or not.
430 */
431 ss = phy_read(phydev, QCA807X_PHY_SPECIFIC_STATUS);
432 if (ss < 0)
433 return ss;
434
435 if (ss & QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED) {
436 int sfc;
437
438 sfc = phy_read(phydev, QCA807X_FUNCTION_CONTROL);
439 if (sfc < 0)
440 return sfc;
441
442 switch (FIELD_GET(QCA807X_SS_SPEED_MASK, ss)) {
443 case QCA807X_SS_SPEED_10:
444 phydev->speed = SPEED_10;
445 break;
446 case QCA807X_SS_SPEED_100:
447 phydev->speed = SPEED_100;
448 break;
449 case QCA807X_SS_SPEED_1000:
450 phydev->speed = SPEED_1000;
451 break;
452 }
453 if (ss & QCA807X_SS_DUPLEX)
454 phydev->duplex = DUPLEX_FULL;
455 else
456 phydev->duplex = DUPLEX_HALF;
457
458 if (ss & QCA807X_SS_MDIX)
459 phydev->mdix = ETH_TP_MDI_X;
460 else
461 phydev->mdix = ETH_TP_MDI;
462
463 switch (FIELD_GET(QCA807X_FC_MDI_CROSSOVER_MODE_MASK, sfc)) {
464 case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI:
465 phydev->mdix_ctrl = ETH_TP_MDI;
466 break;
467 case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX:
468 phydev->mdix_ctrl = ETH_TP_MDI_X;
469 break;
470 case QCA807X_FC_MDI_CROSSOVER_AUTO:
471 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
472 break;
473 }
474 }
475
476 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
477 phy_resolve_aneg_pause(phydev);
478
479 return 0;
480 }
481
482 static int qca807x_read_fiber_status(struct phy_device *phydev)
483 {
484 int ss, err, lpa, old_link = phydev->link;
485
486 /* Update the link, but return if there was an error */
487 err = genphy_update_link(phydev);
488 if (err)
489 return err;
490
491 /* why bother the PHY if nothing can have changed */
492 if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
493 return 0;
494
495 phydev->speed = SPEED_UNKNOWN;
496 phydev->duplex = DUPLEX_UNKNOWN;
497 phydev->pause = 0;
498 phydev->asym_pause = 0;
499
500 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
501 lpa = phy_read(phydev, MII_LPA);
502 if (lpa < 0)
503 return lpa;
504
505 linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
506 phydev->lp_advertising, lpa & LPA_LPACK);
507 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
508 phydev->lp_advertising, lpa & LPA_1000XFULL);
509 linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
510 phydev->lp_advertising, lpa & LPA_1000XPAUSE);
511 linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
512 phydev->lp_advertising,
513 lpa & LPA_1000XPAUSE_ASYM);
514
515 phy_resolve_aneg_linkmode(phydev);
516 }
517
518 /* Read the QCA807x PHY-Specific Status register fiber page,
519 * which indicates the speed and duplex that the PHY is actually
520 * using, irrespective of whether we are in autoneg mode or not.
521 */
522 ss = phy_read(phydev, QCA807X_PHY_SPECIFIC_STATUS);
523 if (ss < 0)
524 return ss;
525
526 if (ss & QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED) {
527 switch (FIELD_GET(QCA807X_SS_SPEED_MASK, ss)) {
528 case QCA807X_SS_SPEED_100:
529 phydev->speed = SPEED_100;
530 break;
531 case QCA807X_SS_SPEED_1000:
532 phydev->speed = SPEED_1000;
533 break;
534 }
535
536 if (ss & QCA807X_SS_DUPLEX)
537 phydev->duplex = DUPLEX_FULL;
538 else
539 phydev->duplex = DUPLEX_HALF;
540 }
541
542 return 0;
543 }
544
545 static int qca807x_read_status(struct phy_device *phydev)
546 {
547 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
548 switch (phydev->port) {
549 case PORT_FIBRE:
550 return qca807x_read_fiber_status(phydev);
551 case PORT_TP:
552 return qca807x_read_copper_status(phydev);
553 default:
554 return -EINVAL;
555 }
556 } else
557 return qca807x_read_copper_status(phydev);
558 }
559
560 static int qca807x_config_intr(struct phy_device *phydev)
561 {
562 int ret, val;
563
564 val = phy_read(phydev, QCA807X_INTR_ENABLE);
565
566 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
567 /* Check for combo port as it has fewer interrupts */
568 if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
569 val |= QCA807X_INTR_ENABLE_SPEED_CHANGED;
570 val |= QCA807X_INTR_ENABLE_LINK_FAIL;
571 val |= QCA807X_INTR_ENABLE_LINK_SUCCESS;
572 } else {
573 val |= QCA807X_INTR_ENABLE_AUTONEG_ERR;
574 val |= QCA807X_INTR_ENABLE_SPEED_CHANGED;
575 val |= QCA807X_INTR_ENABLE_DUPLEX_CHANGED;
576 val |= QCA807X_INTR_ENABLE_LINK_FAIL;
577 val |= QCA807X_INTR_ENABLE_LINK_SUCCESS;
578 }
579 ret = phy_write(phydev, QCA807X_INTR_ENABLE, val);
580 } else {
581 ret = phy_write(phydev, QCA807X_INTR_ENABLE, 0);
582 }
583
584 return ret;
585 }
586
587 #if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)
588 static int qca807x_ack_intr(struct phy_device *phydev)
589 {
590 int ret;
591
592 ret = phy_read(phydev, QCA807X_INTR_STATUS);
593
594 return (ret < 0) ? ret : 0;
595 }
596 #else
597 static irqreturn_t qca807x_handle_interrupt(struct phy_device *phydev)
598 {
599 int irq_status, int_enabled;
600
601 irq_status = phy_read(phydev, QCA807X_INTR_STATUS);
602 if (irq_status < 0) {
603 phy_error(phydev);
604 return IRQ_NONE;
605 }
606
607 /* Read the current enabled interrupts */
608 int_enabled = phy_read(phydev, QCA807X_INTR_ENABLE);
609 if (int_enabled < 0) {
610 phy_error(phydev);
611 return IRQ_NONE;
612 }
613
614 /* See if this was one of our enabled interrupts */
615 if (!(irq_status & int_enabled))
616 return IRQ_NONE;
617
618 phy_trigger_machine(phydev);
619
620 return IRQ_HANDLED;
621 }
622 #endif
623
624 static int qca807x_led_config(struct phy_device *phydev)
625 {
626 struct device_node *node = phydev->mdio.dev.of_node;
627 bool led_config = false;
628 int val;
629
630 val = phy_read_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_LED_1000N_1);
631 if (val < 0)
632 return val;
633
634 if (of_property_read_bool(node, "qcom,single-led-1000")) {
635 val |= QCA807X_LED_TXACT_BLK_EN_2;
636 val |= QCA807X_LED_RXACT_BLK_EN_2;
637 val |= QCA807X_LED_GT_ON_EN_2;
638
639 led_config = true;
640 }
641
642 if (of_property_read_bool(node, "qcom,single-led-100")) {
643 val |= QCA807X_LED_HT_ON_EN_2;
644
645 led_config = true;
646 }
647
648 if (of_property_read_bool(node, "qcom,single-led-10")) {
649 val |= QCA807X_LED_BT_ON_EN_2;
650
651 led_config = true;
652 }
653
654 if (led_config)
655 return phy_write_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_LED_1000N_1, val);
656 else
657 return 0;
658 }
659
660 static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
661 {
662 struct phy_device *phydev = upstream;
663 __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
664 phy_interface_t iface;
665 int ret;
666
667 sfp_parse_support(phydev->sfp_bus, id, support);
668 iface = sfp_select_interface(phydev->sfp_bus, support);
669
670 dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface));
671
672 switch (iface) {
673 case PHY_INTERFACE_MODE_1000BASEX:
674 case PHY_INTERFACE_MODE_100BASEX:
675 /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
676 ret = phy_modify(phydev,
677 QCA807X_CHIP_CONFIGURATION,
678 QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
679 QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
680 /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
681 ret = phy_set_bits_mmd(phydev,
682 MDIO_MMD_AN,
683 QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
684 QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN);
685 /* Select fiber page */
686 ret = phy_clear_bits(phydev,
687 QCA807X_CHIP_CONFIGURATION,
688 QCA807X_BT_BX_REG_SEL);
689
690 phydev->port = PORT_FIBRE;
691 break;
692 default:
693 dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n");
694 return -EINVAL;
695 }
696
697 return ret;
698 }
699
700 static void qca807x_sfp_remove(void *upstream)
701 {
702 struct phy_device *phydev = upstream;
703
704 /* Select copper page */
705 phy_set_bits(phydev,
706 QCA807X_CHIP_CONFIGURATION,
707 QCA807X_BT_BX_REG_SEL);
708
709 phydev->port = PORT_TP;
710 }
711
712 static const struct sfp_upstream_ops qca807x_sfp_ops = {
713 .attach = phy_sfp_attach,
714 .detach = phy_sfp_detach,
715 .module_insert = qca807x_sfp_insert,
716 .module_remove = qca807x_sfp_remove,
717 };
718
719 static int qca807x_config(struct phy_device *phydev)
720 {
721 struct device_node *node = phydev->mdio.dev.of_node;
722 int control_dac, ret = 0;
723 u32 of_control_dac;
724
725 /* Check for Combo port */
726 if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
727 int psgmii_serdes;
728
729 /* Prevent PSGMII going into hibernation via PSGMII self test */
730 psgmii_serdes = phy_read_mmd(phydev, MDIO_MMD_PCS, PSGMII_MMD3_SERDES_CONTROL);
731 psgmii_serdes &= ~BIT(1);
732 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
733 PSGMII_MMD3_SERDES_CONTROL,
734 psgmii_serdes);
735 }
736
737 if (!of_property_read_u32(node, "qcom,control-dac", &of_control_dac)) {
738 control_dac = phy_read_mmd(phydev, MDIO_MMD_AN,
739 QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH);
740 control_dac &= ~QCA807X_CONTROL_DAC_MASK;
741 control_dac |= FIELD_PREP(QCA807X_CONTROL_DAC_MASK, of_control_dac);
742 ret = phy_write_mmd(phydev, MDIO_MMD_AN,
743 QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH,
744 control_dac);
745 }
746
747 /* Optionally configure LED-s */
748 if (IS_ENABLED(CONFIG_GPIOLIB)) {
749 /* Check whether PHY-s pins are used as GPIO-s */
750 if (!of_property_read_bool(node, "gpio-controller"))
751 ret = qca807x_led_config(phydev);
752 } else {
753 ret = qca807x_led_config(phydev);
754 }
755
756 return ret;
757 }
758
759 static int qca807x_probe(struct phy_device *phydev)
760 {
761 struct device_node *node = phydev->mdio.dev.of_node;
762 int ret = 0;
763
764 if (IS_ENABLED(CONFIG_GPIOLIB)) {
765 /* Do not register a GPIO controller unless flagged for it */
766 if (of_property_read_bool(node, "gpio-controller"))
767 ret = qca807x_gpio(phydev);
768 }
769
770 /* Attach SFP bus on combo port*/
771 if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
772 ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
773 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
774 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
775 }
776
777 return ret;
778 }
779
780 static int qca807x_psgmii_config(struct phy_device *phydev)
781 {
782 struct device_node *node = phydev->mdio.dev.of_node;
783 int tx_amp, ret = 0;
784 u32 tx_driver_strength;
785
786 /* Workaround to enable AZ transmitting ability */
787 ret = phy_clear_bits_mmd(phydev,
788 MDIO_MMD_PMAPMD,
789 PSGMII_MODE_CTRL,
790 PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK);
791
792 /* PSGMII/QSGMII TX amp set to DT defined value instead of default 600mV */
793 if (!of_property_read_u32(node, "qcom,tx-driver-strength", &tx_driver_strength)) {
794 tx_amp = phy_read(phydev, PSGMII_QSGMII_DRIVE_CONTROL_1);
795 tx_amp &= ~PSGMII_QSGMII_TX_DRIVER_MASK;
796 tx_amp |= FIELD_PREP(PSGMII_QSGMII_TX_DRIVER_MASK, tx_driver_strength);
797 ret = phy_write(phydev, PSGMII_QSGMII_DRIVE_CONTROL_1, tx_amp);
798 }
799
800 return ret;
801 }
802
803 static struct phy_driver qca807x_drivers[] = {
804 {
805 PHY_ID_MATCH_EXACT(PHY_ID_QCA8072),
806 .name = "Qualcomm QCA8072",
807 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
808 .flags = PHY_POLL_CABLE_TEST,
809 #endif
810 /* PHY_GBIT_FEATURES */
811 .probe = qca807x_probe,
812 .config_init = qca807x_config,
813 .read_status = qca807x_read_status,
814 .config_intr = qca807x_config_intr,
815 #if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)
816 .ack_interrupt = qca807x_ack_intr,
817 #else
818 .handle_interrupt = qca807x_handle_interrupt,
819 #endif
820 .soft_reset = genphy_soft_reset,
821 .get_tunable = qca807x_get_tunable,
822 .set_tunable = qca807x_set_tunable,
823 .resume = genphy_resume,
824 .suspend = genphy_suspend,
825 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
826 .cable_test_start = qca807x_cable_test_start,
827 .cable_test_get_status = qca807x_cable_test_get_status,
828 #endif
829 },
830 {
831 PHY_ID_MATCH_EXACT(PHY_ID_QCA8075),
832 .name = "Qualcomm QCA8075",
833 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
834 .flags = PHY_POLL_CABLE_TEST,
835 #endif
836 /* PHY_GBIT_FEATURES */
837 .probe = qca807x_probe,
838 .config_init = qca807x_config,
839 .read_status = qca807x_read_status,
840 .config_intr = qca807x_config_intr,
841 #if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)
842 .ack_interrupt = qca807x_ack_intr,
843 #else
844 .handle_interrupt = qca807x_handle_interrupt,
845 #endif
846 .soft_reset = genphy_soft_reset,
847 .get_tunable = qca807x_get_tunable,
848 .set_tunable = qca807x_set_tunable,
849 .resume = genphy_resume,
850 .suspend = genphy_suspend,
851 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
852 .cable_test_start = qca807x_cable_test_start,
853 .cable_test_get_status = qca807x_cable_test_get_status,
854 #endif
855 },
856 {
857 PHY_ID_MATCH_EXACT(PHY_ID_QCA807X_PSGMII),
858 .name = "Qualcomm QCA807x PSGMII",
859 .probe = qca807x_psgmii_config,
860 },
861 };
862 module_phy_driver(qca807x_drivers);
863
864 static struct mdio_device_id __maybe_unused qca807x_tbl[] = {
865 { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
866 { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
867 { PHY_ID_MATCH_MODEL(PHY_ID_QCA807X_PSGMII) },
868 { }
869 };
870
871 MODULE_AUTHOR("Robert Marko");
872 MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver");
873 MODULE_DEVICE_TABLE(mdio, qca807x_tbl);
874 MODULE_LICENSE("GPL");