1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2020 Sartura Ltd.
5 * Author: Robert Marko <robert.marko@sartura.hr>
7 * Qualcomm QCA8072 and QCA8075 PHY driver
10 #include <linux/version.h>
11 #include <linux/module.h>
13 #include <linux/phy.h>
14 #include <linux/bitfield.h>
15 #include <linux/ethtool_netlink.h>
16 #include <linux/gpio.h>
17 #include <linux/sfp.h>
19 #include <dt-bindings/net/qcom-qca807x.h>
21 #define PHY_ID_QCA8072 0x004dd0b2
22 #define PHY_ID_QCA8075 0x004dd0b1
23 #define PHY_ID_QCA807X_PSGMII 0x06820805
26 #define QCA807X_SMARTSPEED_EN BIT(5)
27 #define QCA807X_SMARTSPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
28 #define QCA807X_SMARTSPEED_RETRY_LIMIT_DEFAULT 5
29 #define QCA807X_SMARTSPEED_RETRY_LIMIT_MIN 2
30 #define QCA807X_SMARTSPEED_RETRY_LIMIT_MAX 9
32 /* Cable diagnostic test (CDT) */
33 #define QCA807X_CDT 0x16
34 #define QCA807X_CDT_ENABLE BIT(15)
35 #define QCA807X_CDT_ENABLE_INTER_PAIR_SHORT BIT(13)
36 #define QCA807X_CDT_STATUS BIT(11)
37 #define QCA807X_CDT_MMD3_STATUS 0x8064
38 #define QCA807X_CDT_MDI0_STATUS_MASK GENMASK(15, 12)
39 #define QCA807X_CDT_MDI1_STATUS_MASK GENMASK(11, 8)
40 #define QCA807X_CDT_MDI2_STATUS_MASK GENMASK(7, 4)
41 #define QCA807X_CDT_MDI3_STATUS_MASK GENMASK(3, 0)
42 #define QCA807X_CDT_RESULTS_INVALID 0x0
43 #define QCA807X_CDT_RESULTS_OK 0x1
44 #define QCA807X_CDT_RESULTS_OPEN 0x2
45 #define QCA807X_CDT_RESULTS_SAME_SHORT 0x3
46 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK 0x4
47 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK 0x8
48 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK 0xc
49 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN 0x6
50 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN 0xa
51 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN 0xe
52 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT 0x7
53 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT 0xb
54 #define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT 0xf
55 #define QCA807X_CDT_RESULTS_BUSY 0x9
56 #define QCA807X_CDT_MMD3_MDI0_LENGTH 0x8065
57 #define QCA807X_CDT_MMD3_MDI1_LENGTH 0x8066
58 #define QCA807X_CDT_MMD3_MDI2_LENGTH 0x8067
59 #define QCA807X_CDT_MMD3_MDI3_LENGTH 0x8068
60 #define QCA807X_CDT_SAME_SHORT_LENGTH_MASK GENMASK(15, 8)
61 #define QCA807X_CDT_CROSS_SHORT_LENGTH_MASK GENMASK(7, 0)
63 #define QCA807X_CHIP_CONFIGURATION 0x1f
64 #define QCA807X_BT_BX_REG_SEL BIT(15)
65 #define QCA807X_BT_BX_REG_SEL_FIBER 0
66 #define QCA807X_BT_BX_REG_SEL_COPPER 1
67 #define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0)
68 #define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4
69 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3
70 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0
72 #define QCA807X_MEDIA_SELECT_STATUS 0x1a
73 #define QCA807X_MEDIA_DETECTED_COPPER BIT(5)
74 #define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4)
75 #define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3)
77 #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e
78 #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0)
80 #define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a
81 #define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0)
83 #define QCA807X_MMD7_LED_100N_1 0x8074
84 #define QCA807X_MMD7_LED_100N_2 0x8075
85 #define QCA807X_MMD7_LED_1000N_1 0x8076
86 #define QCA807X_MMD7_LED_1000N_2 0x8077
87 #define QCA807X_LED_TXACT_BLK_EN_2 BIT(10)
88 #define QCA807X_LED_RXACT_BLK_EN_2 BIT(9)
89 #define QCA807X_LED_GT_ON_EN_2 BIT(6)
90 #define QCA807X_LED_HT_ON_EN_2 BIT(5)
91 #define QCA807X_LED_BT_ON_EN_2 BIT(4)
92 #define QCA807X_GPIO_FORCE_EN BIT(15)
93 #define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
95 #define QCA807X_INTR_ENABLE 0x12
96 #define QCA807X_INTR_STATUS 0x13
97 #define QCA807X_INTR_ENABLE_AUTONEG_ERR BIT(15)
98 #define QCA807X_INTR_ENABLE_SPEED_CHANGED BIT(14)
99 #define QCA807X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
100 #define QCA807X_INTR_ENABLE_LINK_FAIL BIT(11)
101 #define QCA807X_INTR_ENABLE_LINK_SUCCESS BIT(10)
103 #define QCA807X_FUNCTION_CONTROL 0x10
104 #define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
105 #define QCA807X_FC_MDI_CROSSOVER_AUTO 3
106 #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1
107 #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0
109 #define QCA807X_PHY_SPECIFIC_STATUS 0x11
110 #define QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED BIT(11)
111 #define QCA807X_SS_SPEED_MASK GENMASK(15, 14)
112 #define QCA807X_SS_SPEED_1000 2
113 #define QCA807X_SS_SPEED_100 1
114 #define QCA807X_SS_SPEED_10 0
115 #define QCA807X_SS_DUPLEX BIT(13)
116 #define QCA807X_SS_MDIX BIT(6)
118 /* PSGMII PHY specific */
119 #define PSGMII_QSGMII_DRIVE_CONTROL_1 0xb
120 #define PSGMII_QSGMII_TX_DRIVER_MASK GENMASK(7, 4)
121 #define PSGMII_MODE_CTRL 0x6d
122 #define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0)
123 #define PSGMII_MMD3_SERDES_CONTROL 0x805a
125 struct qca807x_gpio_priv
{
126 struct phy_device
*phy
;
129 static int qca807x_get_downshift(struct phy_device
*phydev
, u8
*data
)
131 int val
, cnt
, enable
;
133 val
= phy_read(phydev
, MII_NWAYTEST
);
137 enable
= FIELD_GET(QCA807X_SMARTSPEED_EN
, val
);
138 cnt
= FIELD_GET(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK
, val
) + 2;
140 *data
= enable
? cnt
: DOWNSHIFT_DEV_DISABLE
;
145 static int qca807x_set_downshift(struct phy_device
*phydev
, u8 cnt
)
149 if (cnt
> QCA807X_SMARTSPEED_RETRY_LIMIT_MAX
||
150 (cnt
< QCA807X_SMARTSPEED_RETRY_LIMIT_MIN
&& cnt
!= DOWNSHIFT_DEV_DISABLE
))
154 ret
= phy_clear_bits(phydev
, MII_NWAYTEST
, QCA807X_SMARTSPEED_EN
);
156 val
= QCA807X_SMARTSPEED_EN
;
157 val
|= FIELD_PREP(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK
, cnt
- 2);
159 phy_modify(phydev
, MII_NWAYTEST
,
160 QCA807X_SMARTSPEED_EN
|
161 QCA807X_SMARTSPEED_RETRY_LIMIT_MASK
,
165 ret
= genphy_soft_reset(phydev
);
170 static int qca807x_get_tunable(struct phy_device
*phydev
,
171 struct ethtool_tunable
*tuna
, void *data
)
174 case ETHTOOL_PHY_DOWNSHIFT
:
175 return qca807x_get_downshift(phydev
, data
);
181 static int qca807x_set_tunable(struct phy_device
*phydev
,
182 struct ethtool_tunable
*tuna
, const void *data
)
185 case ETHTOOL_PHY_DOWNSHIFT
:
186 return qca807x_set_downshift(phydev
, *(const u8
*)data
);
192 static bool qca807x_distance_valid(int result
)
195 case QCA807X_CDT_RESULTS_OPEN
:
196 case QCA807X_CDT_RESULTS_SAME_SHORT
:
197 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK
:
198 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK
:
199 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK
:
200 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN
:
201 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN
:
202 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN
:
203 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT
:
204 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT
:
205 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT
:
211 static int qca807x_report_length(struct phy_device
*phydev
,
212 int pair
, int result
)
217 ret
= phy_read_mmd(phydev
, MDIO_MMD_PCS
, QCA807X_CDT_MMD3_MDI0_LENGTH
+ pair
);
222 case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT
:
223 length
= (FIELD_GET(QCA807X_CDT_SAME_SHORT_LENGTH_MASK
, ret
) * 800) / 10;
225 case ETHTOOL_A_CABLE_RESULT_CODE_OPEN
:
226 case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT
:
227 length
= (FIELD_GET(QCA807X_CDT_CROSS_SHORT_LENGTH_MASK
, ret
) * 800) / 10;
231 ethnl_cable_test_fault_length(phydev
, pair
, length
);
236 static int qca807x_cable_test_report_trans(int result
)
239 case QCA807X_CDT_RESULTS_OK
:
240 return ETHTOOL_A_CABLE_RESULT_CODE_OK
;
241 case QCA807X_CDT_RESULTS_OPEN
:
242 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN
;
243 case QCA807X_CDT_RESULTS_SAME_SHORT
:
244 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT
;
245 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK
:
246 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK
:
247 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK
:
248 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN
:
249 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN
:
250 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN
:
251 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT
:
252 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT
:
253 case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT
:
254 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT
;
256 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC
;
260 static int qca807x_cable_test_report(struct phy_device
*phydev
)
262 int pair0
, pair1
, pair2
, pair3
;
265 ret
= phy_read_mmd(phydev
, MDIO_MMD_PCS
, QCA807X_CDT_MMD3_STATUS
);
269 pair0
= FIELD_GET(QCA807X_CDT_MDI0_STATUS_MASK
, ret
);
270 pair1
= FIELD_GET(QCA807X_CDT_MDI1_STATUS_MASK
, ret
);
271 pair2
= FIELD_GET(QCA807X_CDT_MDI2_STATUS_MASK
, ret
);
272 pair3
= FIELD_GET(QCA807X_CDT_MDI3_STATUS_MASK
, ret
);
274 ethnl_cable_test_result(phydev
, ETHTOOL_A_CABLE_PAIR_A
,
275 qca807x_cable_test_report_trans(pair0
));
276 ethnl_cable_test_result(phydev
, ETHTOOL_A_CABLE_PAIR_B
,
277 qca807x_cable_test_report_trans(pair1
));
278 ethnl_cable_test_result(phydev
, ETHTOOL_A_CABLE_PAIR_C
,
279 qca807x_cable_test_report_trans(pair2
));
280 ethnl_cable_test_result(phydev
, ETHTOOL_A_CABLE_PAIR_D
,
281 qca807x_cable_test_report_trans(pair3
));
283 if (qca807x_distance_valid(pair0
))
284 qca807x_report_length(phydev
, 0, qca807x_cable_test_report_trans(pair0
));
285 if (qca807x_distance_valid(pair1
))
286 qca807x_report_length(phydev
, 1, qca807x_cable_test_report_trans(pair1
));
287 if (qca807x_distance_valid(pair2
))
288 qca807x_report_length(phydev
, 2, qca807x_cable_test_report_trans(pair2
));
289 if (qca807x_distance_valid(pair3
))
290 qca807x_report_length(phydev
, 3, qca807x_cable_test_report_trans(pair3
));
295 static int qca807x_cable_test_get_status(struct phy_device
*phydev
,
302 val
= phy_read(phydev
, QCA807X_CDT
);
303 if (!((val
& QCA807X_CDT_ENABLE
) && (val
& QCA807X_CDT_STATUS
))) {
306 return qca807x_cable_test_report(phydev
);
312 static int qca807x_cable_test_start(struct phy_device
*phydev
)
316 val
= phy_read(phydev
, QCA807X_CDT
);
317 /* Enable inter-pair short check as well */
318 val
&= ~QCA807X_CDT_ENABLE_INTER_PAIR_SHORT
;
319 val
|= QCA807X_CDT_ENABLE
;
320 ret
= phy_write(phydev
, QCA807X_CDT
, val
);
325 #ifdef CONFIG_GPIOLIB
326 static int qca807x_gpio_get_direction(struct gpio_chip
*gc
, unsigned int offset
)
328 return GPIO_LINE_DIRECTION_OUT
;
331 static int qca807x_gpio_get_reg(unsigned int offset
)
333 return QCA807X_MMD7_LED_100N_2
+ (offset
% 2) * 2;
336 static int qca807x_gpio_get(struct gpio_chip
*gc
, unsigned int offset
)
338 struct qca807x_gpio_priv
*priv
= gpiochip_get_data(gc
);
341 val
= phy_read_mmd(priv
->phy
, MDIO_MMD_AN
, qca807x_gpio_get_reg(offset
));
343 return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK
, val
);
346 static void qca807x_gpio_set(struct gpio_chip
*gc
, unsigned int offset
, int value
)
348 struct qca807x_gpio_priv
*priv
= gpiochip_get_data(gc
);
351 val
= phy_read_mmd(priv
->phy
, MDIO_MMD_AN
, qca807x_gpio_get_reg(offset
));
352 val
&= ~QCA807X_GPIO_FORCE_MODE_MASK
;
353 val
|= QCA807X_GPIO_FORCE_EN
;
354 val
|= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK
, value
);
356 phy_write_mmd(priv
->phy
, MDIO_MMD_AN
, qca807x_gpio_get_reg(offset
), val
);
359 static int qca807x_gpio_dir_out(struct gpio_chip
*gc
, unsigned int offset
, int value
)
361 qca807x_gpio_set(gc
, offset
, value
);
366 static int qca807x_gpio(struct phy_device
*phydev
)
368 struct device
*dev
= &phydev
->mdio
.dev
;
369 struct qca807x_gpio_priv
*priv
;
370 struct gpio_chip
*gc
;
372 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
378 gc
= devm_kzalloc(dev
, sizeof(*gc
), GFP_KERNEL
);
382 gc
->label
= dev_name(dev
);
386 gc
->owner
= THIS_MODULE
;
387 gc
->can_sleep
= true;
388 gc
->get_direction
= qca807x_gpio_get_direction
;
389 gc
->direction_output
= qca807x_gpio_dir_out
;
390 gc
->get
= qca807x_gpio_get
;
391 gc
->set
= qca807x_gpio_set
;
393 return devm_gpiochip_add_data(dev
, gc
, priv
);
397 static int qca807x_read_copper_status(struct phy_device
*phydev
)
399 int ss
, err
, old_link
= phydev
->link
;
401 /* Update the link, but return if there was an error */
402 err
= genphy_update_link(phydev
);
406 /* why bother the PHY if nothing can have changed */
407 if (phydev
->autoneg
== AUTONEG_ENABLE
&& old_link
&& phydev
->link
)
410 phydev
->speed
= SPEED_UNKNOWN
;
411 phydev
->duplex
= DUPLEX_UNKNOWN
;
413 phydev
->asym_pause
= 0;
415 err
= genphy_read_lpa(phydev
);
419 /* Read the QCA807x PHY-Specific Status register copper page,
420 * which indicates the speed and duplex that the PHY is actually
421 * using, irrespective of whether we are in autoneg mode or not.
423 ss
= phy_read(phydev
, QCA807X_PHY_SPECIFIC_STATUS
);
427 if (ss
& QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED
) {
430 sfc
= phy_read(phydev
, QCA807X_FUNCTION_CONTROL
);
434 switch (FIELD_GET(QCA807X_SS_SPEED_MASK
, ss
)) {
435 case QCA807X_SS_SPEED_10
:
436 phydev
->speed
= SPEED_10
;
438 case QCA807X_SS_SPEED_100
:
439 phydev
->speed
= SPEED_100
;
441 case QCA807X_SS_SPEED_1000
:
442 phydev
->speed
= SPEED_1000
;
445 if (ss
& QCA807X_SS_DUPLEX
)
446 phydev
->duplex
= DUPLEX_FULL
;
448 phydev
->duplex
= DUPLEX_HALF
;
450 if (ss
& QCA807X_SS_MDIX
)
451 phydev
->mdix
= ETH_TP_MDI_X
;
453 phydev
->mdix
= ETH_TP_MDI
;
455 switch (FIELD_GET(QCA807X_FC_MDI_CROSSOVER_MODE_MASK
, sfc
)) {
456 case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI
:
457 phydev
->mdix_ctrl
= ETH_TP_MDI
;
459 case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX
:
460 phydev
->mdix_ctrl
= ETH_TP_MDI_X
;
462 case QCA807X_FC_MDI_CROSSOVER_AUTO
:
463 phydev
->mdix_ctrl
= ETH_TP_MDI_AUTO
;
468 if (phydev
->autoneg
== AUTONEG_ENABLE
&& phydev
->autoneg_complete
)
469 phy_resolve_aneg_pause(phydev
);
474 static int qca807x_read_fiber_status(struct phy_device
*phydev
)
476 int ss
, err
, lpa
, old_link
= phydev
->link
;
478 /* Update the link, but return if there was an error */
479 err
= genphy_update_link(phydev
);
483 /* why bother the PHY if nothing can have changed */
484 if (phydev
->autoneg
== AUTONEG_ENABLE
&& old_link
&& phydev
->link
)
487 phydev
->speed
= SPEED_UNKNOWN
;
488 phydev
->duplex
= DUPLEX_UNKNOWN
;
490 phydev
->asym_pause
= 0;
492 if (phydev
->autoneg
== AUTONEG_ENABLE
&& phydev
->autoneg_complete
) {
493 lpa
= phy_read(phydev
, MII_LPA
);
497 linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT
,
498 phydev
->lp_advertising
, lpa
& LPA_LPACK
);
499 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT
,
500 phydev
->lp_advertising
, lpa
& LPA_1000XFULL
);
501 linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT
,
502 phydev
->lp_advertising
, lpa
& LPA_1000XPAUSE
);
503 linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT
,
504 phydev
->lp_advertising
,
505 lpa
& LPA_1000XPAUSE_ASYM
);
507 phy_resolve_aneg_linkmode(phydev
);
510 /* Read the QCA807x PHY-Specific Status register fiber page,
511 * which indicates the speed and duplex that the PHY is actually
512 * using, irrespective of whether we are in autoneg mode or not.
514 ss
= phy_read(phydev
, QCA807X_PHY_SPECIFIC_STATUS
);
518 if (ss
& QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED
) {
519 switch (FIELD_GET(QCA807X_SS_SPEED_MASK
, ss
)) {
520 case QCA807X_SS_SPEED_100
:
521 phydev
->speed
= SPEED_100
;
523 case QCA807X_SS_SPEED_1000
:
524 phydev
->speed
= SPEED_1000
;
528 if (ss
& QCA807X_SS_DUPLEX
)
529 phydev
->duplex
= DUPLEX_FULL
;
531 phydev
->duplex
= DUPLEX_HALF
;
537 static int qca807x_read_status(struct phy_device
*phydev
)
539 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT
, phydev
->supported
)) {
540 switch (phydev
->port
) {
542 return qca807x_read_fiber_status(phydev
);
544 return qca807x_read_copper_status(phydev
);
549 return qca807x_read_copper_status(phydev
);
552 static int qca807x_config_intr(struct phy_device
*phydev
)
556 val
= phy_read(phydev
, QCA807X_INTR_ENABLE
);
558 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
) {
559 /* Check for combo port as it has fewer interrupts */
560 if (phy_read(phydev
, QCA807X_CHIP_CONFIGURATION
)) {
561 val
|= QCA807X_INTR_ENABLE_SPEED_CHANGED
;
562 val
|= QCA807X_INTR_ENABLE_LINK_FAIL
;
563 val
|= QCA807X_INTR_ENABLE_LINK_SUCCESS
;
565 val
|= QCA807X_INTR_ENABLE_AUTONEG_ERR
;
566 val
|= QCA807X_INTR_ENABLE_SPEED_CHANGED
;
567 val
|= QCA807X_INTR_ENABLE_DUPLEX_CHANGED
;
568 val
|= QCA807X_INTR_ENABLE_LINK_FAIL
;
569 val
|= QCA807X_INTR_ENABLE_LINK_SUCCESS
;
571 ret
= phy_write(phydev
, QCA807X_INTR_ENABLE
, val
);
573 ret
= phy_write(phydev
, QCA807X_INTR_ENABLE
, 0);
579 static irqreturn_t
qca807x_handle_interrupt(struct phy_device
*phydev
)
581 int irq_status
, int_enabled
;
583 irq_status
= phy_read(phydev
, QCA807X_INTR_STATUS
);
584 if (irq_status
< 0) {
589 /* Read the current enabled interrupts */
590 int_enabled
= phy_read(phydev
, QCA807X_INTR_ENABLE
);
591 if (int_enabled
< 0) {
596 /* See if this was one of our enabled interrupts */
597 if (!(irq_status
& int_enabled
))
600 phy_trigger_machine(phydev
);
605 static int qca807x_led_config(struct phy_device
*phydev
)
607 struct device_node
*node
= phydev
->mdio
.dev
.of_node
;
608 bool led_config
= false;
611 val
= phy_read_mmd(phydev
, MDIO_MMD_AN
, QCA807X_MMD7_LED_1000N_1
);
615 if (of_property_read_bool(node
, "qcom,single-led-1000")) {
616 val
|= QCA807X_LED_TXACT_BLK_EN_2
;
617 val
|= QCA807X_LED_RXACT_BLK_EN_2
;
618 val
|= QCA807X_LED_GT_ON_EN_2
;
623 if (of_property_read_bool(node
, "qcom,single-led-100")) {
624 val
|= QCA807X_LED_HT_ON_EN_2
;
629 if (of_property_read_bool(node
, "qcom,single-led-10")) {
630 val
|= QCA807X_LED_BT_ON_EN_2
;
636 return phy_write_mmd(phydev
, MDIO_MMD_AN
, QCA807X_MMD7_LED_1000N_1
, val
);
641 static int qca807x_sfp_insert(void *upstream
, const struct sfp_eeprom_id
*id
)
643 struct phy_device
*phydev
= upstream
;
644 __ETHTOOL_DECLARE_LINK_MODE_MASK(support
) = { 0, };
645 phy_interface_t iface
;
647 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)
648 DECLARE_PHY_INTERFACE_MASK(interfaces
);
650 sfp_parse_support(phydev
->sfp_bus
, id
, support
, interfaces
);
652 sfp_parse_support(phydev
->sfp_bus
, id
, support
);
654 iface
= sfp_select_interface(phydev
->sfp_bus
, support
);
656 dev_info(&phydev
->mdio
.dev
, "%s SFP module inserted\n", phy_modes(iface
));
659 case PHY_INTERFACE_MODE_1000BASEX
:
660 case PHY_INTERFACE_MODE_100BASEX
:
661 /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
662 ret
= phy_modify(phydev
,
663 QCA807X_CHIP_CONFIGURATION
,
664 QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK
,
665 QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER
);
666 /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
667 ret
= phy_set_bits_mmd(phydev
,
669 QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION
,
670 QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN
);
671 /* Select fiber page */
672 ret
= phy_clear_bits(phydev
,
673 QCA807X_CHIP_CONFIGURATION
,
674 QCA807X_BT_BX_REG_SEL
);
676 phydev
->port
= PORT_FIBRE
;
679 dev_err(&phydev
->mdio
.dev
, "Incompatible SFP module inserted\n");
686 static void qca807x_sfp_remove(void *upstream
)
688 struct phy_device
*phydev
= upstream
;
690 /* Select copper page */
692 QCA807X_CHIP_CONFIGURATION
,
693 QCA807X_BT_BX_REG_SEL
);
695 phydev
->port
= PORT_TP
;
698 static const struct sfp_upstream_ops qca807x_sfp_ops
= {
699 .attach
= phy_sfp_attach
,
700 .detach
= phy_sfp_detach
,
701 .module_insert
= qca807x_sfp_insert
,
702 .module_remove
= qca807x_sfp_remove
,
705 static int qca807x_config(struct phy_device
*phydev
)
707 struct device_node
*node
= phydev
->mdio
.dev
.of_node
;
708 int control_dac
, ret
= 0;
711 /* Check for Combo port */
712 if (phy_read(phydev
, QCA807X_CHIP_CONFIGURATION
)) {
715 /* Prevent PSGMII going into hibernation via PSGMII self test */
716 psgmii_serdes
= phy_read_mmd(phydev
, MDIO_MMD_PCS
, PSGMII_MMD3_SERDES_CONTROL
);
717 psgmii_serdes
&= ~BIT(1);
718 ret
= phy_write_mmd(phydev
, MDIO_MMD_PCS
,
719 PSGMII_MMD3_SERDES_CONTROL
,
723 if (!of_property_read_u32(node
, "qcom,control-dac", &of_control_dac
)) {
724 control_dac
= phy_read_mmd(phydev
, MDIO_MMD_AN
,
725 QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH
);
726 control_dac
&= ~QCA807X_CONTROL_DAC_MASK
;
727 control_dac
|= FIELD_PREP(QCA807X_CONTROL_DAC_MASK
, of_control_dac
);
728 ret
= phy_write_mmd(phydev
, MDIO_MMD_AN
,
729 QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH
,
733 /* Optionally configure LED-s */
734 if (IS_ENABLED(CONFIG_GPIOLIB
)) {
735 /* Check whether PHY-s pins are used as GPIO-s */
736 if (!of_property_read_bool(node
, "gpio-controller"))
737 ret
= qca807x_led_config(phydev
);
739 ret
= qca807x_led_config(phydev
);
745 static int qca807x_probe(struct phy_device
*phydev
)
747 struct device_node
*node
= phydev
->mdio
.dev
.of_node
;
750 if (IS_ENABLED(CONFIG_GPIOLIB
)) {
751 /* Do not register a GPIO controller unless flagged for it */
752 if (of_property_read_bool(node
, "gpio-controller"))
753 ret
= qca807x_gpio(phydev
);
756 /* Attach SFP bus on combo port*/
757 if (phy_read(phydev
, QCA807X_CHIP_CONFIGURATION
)) {
758 ret
= phy_sfp_probe(phydev
, &qca807x_sfp_ops
);
759 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT
, phydev
->supported
);
760 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT
, phydev
->advertising
);
766 static int qca807x_psgmii_config(struct phy_device
*phydev
)
768 struct device_node
*node
= phydev
->mdio
.dev
.of_node
;
770 u32 tx_driver_strength
;
772 /* Workaround to enable AZ transmitting ability */
773 ret
= phy_clear_bits_mmd(phydev
,
776 PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK
);
778 /* PSGMII/QSGMII TX amp set to DT defined value instead of default 600mV */
779 if (!of_property_read_u32(node
, "qcom,tx-driver-strength", &tx_driver_strength
)) {
780 tx_amp
= phy_read(phydev
, PSGMII_QSGMII_DRIVE_CONTROL_1
);
781 tx_amp
&= ~PSGMII_QSGMII_TX_DRIVER_MASK
;
782 tx_amp
|= FIELD_PREP(PSGMII_QSGMII_TX_DRIVER_MASK
, tx_driver_strength
);
783 ret
= phy_write(phydev
, PSGMII_QSGMII_DRIVE_CONTROL_1
, tx_amp
);
789 static struct phy_driver qca807x_drivers
[] = {
791 PHY_ID_MATCH_EXACT(PHY_ID_QCA8072
),
792 .name
= "Qualcomm QCA8072",
793 .flags
= PHY_POLL_CABLE_TEST
,
794 /* PHY_GBIT_FEATURES */
795 .probe
= qca807x_probe
,
796 .config_init
= qca807x_config
,
797 .read_status
= qca807x_read_status
,
798 .config_intr
= qca807x_config_intr
,
799 .handle_interrupt
= qca807x_handle_interrupt
,
800 .soft_reset
= genphy_soft_reset
,
801 .get_tunable
= qca807x_get_tunable
,
802 .set_tunable
= qca807x_set_tunable
,
803 .resume
= genphy_resume
,
804 .suspend
= genphy_suspend
,
805 .cable_test_start
= qca807x_cable_test_start
,
806 .cable_test_get_status
= qca807x_cable_test_get_status
,
809 PHY_ID_MATCH_EXACT(PHY_ID_QCA8075
),
810 .name
= "Qualcomm QCA8075",
811 .flags
= PHY_POLL_CABLE_TEST
,
812 /* PHY_GBIT_FEATURES */
813 .probe
= qca807x_probe
,
814 .config_init
= qca807x_config
,
815 .read_status
= qca807x_read_status
,
816 .config_intr
= qca807x_config_intr
,
817 .handle_interrupt
= qca807x_handle_interrupt
,
818 .soft_reset
= genphy_soft_reset
,
819 .get_tunable
= qca807x_get_tunable
,
820 .set_tunable
= qca807x_set_tunable
,
821 .resume
= genphy_resume
,
822 .suspend
= genphy_suspend
,
823 .cable_test_start
= qca807x_cable_test_start
,
824 .cable_test_get_status
= qca807x_cable_test_get_status
,
827 PHY_ID_MATCH_EXACT(PHY_ID_QCA807X_PSGMII
),
828 .name
= "Qualcomm QCA807x PSGMII",
829 .probe
= qca807x_psgmii_config
,
832 module_phy_driver(qca807x_drivers
);
834 static struct mdio_device_id __maybe_unused qca807x_tbl
[] = {
835 { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072
) },
836 { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075
) },
837 { PHY_ID_MATCH_MODEL(PHY_ID_QCA807X_PSGMII
) },
841 MODULE_AUTHOR("Robert Marko");
842 MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver");
843 MODULE_DEVICE_TABLE(mdio
, qca807x_tbl
);
844 MODULE_LICENSE("GPL");