1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* Driver for the Texas Instruments DP83TG720 PHY |
3 | * Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> |
4 | */ |
5 | #include <linux/bitfield.h> |
6 | #include <linux/ethtool_netlink.h> |
7 | #include <linux/jiffies.h> |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/phy.h> |
11 | #include <linux/random.h> |
12 | |
13 | #include "open_alliance_helpers.h" |
14 | |
15 | /* |
16 | * DP83TG720S_POLL_ACTIVE_LINK - Polling interval in milliseconds when the link |
17 | * is active. |
18 | * DP83TG720S_POLL_NO_LINK_MIN - Minimum polling interval in milliseconds when |
19 | * the link is down. |
20 | * DP83TG720S_POLL_NO_LINK_MAX - Maximum polling interval in milliseconds when |
21 | * the link is down. |
22 | * |
23 | * These values are not documented or officially recommended by the vendor but |
24 | * were determined through empirical testing. They achieve a good balance in |
25 | * minimizing the number of reset retries while ensuring reliable link recovery |
26 | * within a reasonable timeframe. |
27 | */ |
28 | #define DP83TG720S_POLL_ACTIVE_LINK 1000 |
29 | #define DP83TG720S_POLL_NO_LINK_MIN 100 |
30 | #define DP83TG720S_POLL_NO_LINK_MAX 1000 |
31 | |
32 | #define DP83TG720S_PHY_ID 0x2000a284 |
33 | |
34 | /* MDIO_MMD_VEND2 registers */ |
35 | #define DP83TG720S_MII_REG_10 0x10 |
36 | #define DP83TG720S_STS_MII_INT BIT(7) |
37 | #define DP83TG720S_LINK_STATUS BIT(0) |
38 | |
39 | /* TDR Configuration Register (0x1E) */ |
40 | #define DP83TG720S_TDR_CFG 0x1e |
41 | /* 1b = TDR start, 0b = No TDR */ |
42 | #define DP83TG720S_TDR_START BIT(15) |
43 | /* 1b = TDR auto on link down, 0b = Manual TDR start */ |
44 | #define DP83TG720S_CFG_TDR_AUTO_RUN BIT(14) |
45 | /* 1b = TDR done, 0b = TDR in progress */ |
46 | #define DP83TG720S_TDR_DONE BIT(1) |
47 | /* 1b = TDR fail, 0b = TDR success */ |
48 | #define DP83TG720S_TDR_FAIL BIT(0) |
49 | |
50 | #define DP83TG720S_PHY_RESET 0x1f |
51 | #define DP83TG720S_HW_RESET BIT(15) |
52 | |
53 | #define DP83TG720S_LPS_CFG3 0x18c |
54 | /* Power modes are documented as bit fields but used as values */ |
55 | /* Power Mode 0 is Normal mode */ |
56 | #define DP83TG720S_LPS_CFG3_PWR_MODE_0 BIT(0) |
57 | |
58 | /* Open Aliance 1000BaseT1 compatible HDD.TDR Fault Status Register */ |
59 | #define DP83TG720S_TDR_FAULT_STATUS 0x30f |
60 | |
61 | /* Register 0x0301: TDR Configuration 2 */ |
62 | #define DP83TG720S_TDR_CFG2 0x301 |
63 | |
64 | /* Register 0x0303: TDR Configuration 3 */ |
65 | #define DP83TG720S_TDR_CFG3 0x303 |
66 | |
67 | /* Register 0x0304: TDR Configuration 4 */ |
68 | #define DP83TG720S_TDR_CFG4 0x304 |
69 | |
70 | /* Register 0x0405: Unknown Register */ |
71 | #define DP83TG720S_UNKNOWN_0405 0x405 |
72 | |
73 | #define DP83TG720S_LINK_QUAL_3 0x547 |
74 | #define DP83TG720S_LINK_LOSS_CNT_MASK GENMASK(15, 10) |
75 | |
76 | /* Register 0x0576: TDR Master Link Down Control */ |
77 | #define DP83TG720S_TDR_MASTER_LINK_DOWN 0x576 |
78 | |
79 | #define DP83TG720S_RGMII_DELAY_CTRL 0x602 |
80 | /* In RGMII mode, Enable or disable the internal delay for RXD */ |
81 | #define DP83TG720S_RGMII_RX_CLK_SEL BIT(1) |
82 | /* In RGMII mode, Enable or disable the internal delay for TXD */ |
83 | #define DP83TG720S_RGMII_TX_CLK_SEL BIT(0) |
84 | |
85 | /* |
86 | * DP83TG720S_PKT_STAT_x registers correspond to similarly named registers |
87 | * in the datasheet (PKT_STAT_1 through PKT_STAT_6). These registers store |
88 | * 32-bit or 16-bit counters for TX and RX statistics and must be read in |
89 | * sequence to ensure the counters are cleared correctly. |
90 | * |
91 | * - DP83TG720S_PKT_STAT_1: Contains TX packet count bits [15:0]. |
92 | * - DP83TG720S_PKT_STAT_2: Contains TX packet count bits [31:16]. |
93 | * - DP83TG720S_PKT_STAT_3: Contains TX error packet count. |
94 | * - DP83TG720S_PKT_STAT_4: Contains RX packet count bits [15:0]. |
95 | * - DP83TG720S_PKT_STAT_5: Contains RX packet count bits [31:16]. |
96 | * - DP83TG720S_PKT_STAT_6: Contains RX error packet count. |
97 | * |
98 | * Keeping the register names as defined in the datasheet helps maintain |
99 | * clarity and alignment with the documentation. |
100 | */ |
101 | #define DP83TG720S_PKT_STAT_1 0x639 |
102 | #define DP83TG720S_PKT_STAT_2 0x63a |
103 | #define DP83TG720S_PKT_STAT_3 0x63b |
104 | #define DP83TG720S_PKT_STAT_4 0x63c |
105 | #define DP83TG720S_PKT_STAT_5 0x63d |
106 | #define DP83TG720S_PKT_STAT_6 0x63e |
107 | |
108 | /* Register 0x083F: Unknown Register */ |
109 | #define DP83TG720S_UNKNOWN_083F 0x83f |
110 | |
111 | #define DP83TG720S_SQI_REG_1 0x871 |
112 | #define DP83TG720S_SQI_OUT_WORST GENMASK(7, 5) |
113 | #define DP83TG720S_SQI_OUT GENMASK(3, 1) |
114 | |
115 | #define DP83TG720_SQI_MAX 7 |
116 | |
117 | struct dp83tg720_stats { |
118 | u64 link_loss_cnt; |
119 | u64 tx_pkt_cnt; |
120 | u64 tx_err_pkt_cnt; |
121 | u64 rx_pkt_cnt; |
122 | u64 rx_err_pkt_cnt; |
123 | }; |
124 | |
125 | struct dp83tg720_priv { |
126 | struct dp83tg720_stats stats; |
127 | }; |
128 | |
129 | /** |
130 | * dp83tg720_update_stats - Update the PHY statistics for the DP83TD510 PHY. |
131 | * @phydev: Pointer to the phy_device structure. |
132 | * |
133 | * The function reads the PHY statistics registers and updates the statistics |
134 | * structure. |
135 | * |
136 | * Returns: 0 on success or a negative error code on failure. |
137 | */ |
138 | static int dp83tg720_update_stats(struct phy_device *phydev) |
139 | { |
140 | struct dp83tg720_priv *priv = phydev->priv; |
141 | u32 count; |
142 | int ret; |
143 | |
144 | /* Read the link loss count */ |
145 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_LINK_QUAL_3); |
146 | if (ret < 0) |
147 | return ret; |
148 | /* link_loss_cnt */ |
149 | count = FIELD_GET(DP83TG720S_LINK_LOSS_CNT_MASK, ret); |
150 | priv->stats.link_loss_cnt += count; |
151 | |
152 | /* The DP83TG720S_PKT_STAT registers are divided into two groups: |
153 | * - Group 1 (TX stats): DP83TG720S_PKT_STAT_1 to DP83TG720S_PKT_STAT_3 |
154 | * - Group 2 (RX stats): DP83TG720S_PKT_STAT_4 to DP83TG720S_PKT_STAT_6 |
155 | * |
156 | * Registers in each group are cleared only after reading them in a |
157 | * plain sequence (e.g., 1, 2, 3 for Group 1 or 4, 5, 6 for Group 2). |
158 | * Any deviation from the sequence, such as reading 1, 2, 1, 2, 3, will |
159 | * prevent the group from being cleared. Additionally, the counters |
160 | * for a group are frozen as soon as the first register in that group |
161 | * is accessed. |
162 | */ |
163 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_1); |
164 | if (ret < 0) |
165 | return ret; |
166 | /* tx_pkt_cnt_15_0 */ |
167 | count = ret; |
168 | |
169 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_2); |
170 | if (ret < 0) |
171 | return ret; |
172 | /* tx_pkt_cnt_31_16 */ |
173 | count |= ret << 16; |
174 | priv->stats.tx_pkt_cnt += count; |
175 | |
176 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_3); |
177 | if (ret < 0) |
178 | return ret; |
179 | /* tx_err_pkt_cnt */ |
180 | priv->stats.tx_err_pkt_cnt += ret; |
181 | |
182 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_4); |
183 | if (ret < 0) |
184 | return ret; |
185 | /* rx_pkt_cnt_15_0 */ |
186 | count = ret; |
187 | |
188 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_5); |
189 | if (ret < 0) |
190 | return ret; |
191 | /* rx_pkt_cnt_31_16 */ |
192 | count |= ret << 16; |
193 | priv->stats.rx_pkt_cnt += count; |
194 | |
195 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_6); |
196 | if (ret < 0) |
197 | return ret; |
198 | /* rx_err_pkt_cnt */ |
199 | priv->stats.rx_err_pkt_cnt += ret; |
200 | |
201 | return 0; |
202 | } |
203 | |
204 | static void dp83tg720_get_link_stats(struct phy_device *phydev, |
205 | struct ethtool_link_ext_stats *link_stats) |
206 | { |
207 | struct dp83tg720_priv *priv = phydev->priv; |
208 | |
209 | link_stats->link_down_events = priv->stats.link_loss_cnt; |
210 | } |
211 | |
212 | static void dp83tg720_get_phy_stats(struct phy_device *phydev, |
213 | struct ethtool_eth_phy_stats *eth_stats, |
214 | struct ethtool_phy_stats *stats) |
215 | { |
216 | struct dp83tg720_priv *priv = phydev->priv; |
217 | |
218 | stats->tx_packets = priv->stats.tx_pkt_cnt; |
219 | stats->tx_errors = priv->stats.tx_err_pkt_cnt; |
220 | stats->rx_packets = priv->stats.rx_pkt_cnt; |
221 | stats->rx_errors = priv->stats.rx_err_pkt_cnt; |
222 | } |
223 | |
224 | /** |
225 | * dp83tg720_cable_test_start - Start the cable test for the DP83TG720 PHY. |
226 | * @phydev: Pointer to the phy_device structure. |
227 | * |
228 | * This sequence is based on the documented procedure for the DP83TG720 PHY. |
229 | * |
230 | * Returns: 0 on success, a negative error code on failure. |
231 | */ |
232 | static int dp83tg720_cable_test_start(struct phy_device *phydev) |
233 | { |
234 | int ret; |
235 | |
236 | /* Initialize the PHY to run the TDR test as described in the |
237 | * "DP83TG720S-Q1: Configuring for Open Alliance Specification |
238 | * Compliance (Rev. B)" application note. |
239 | * Most of the registers are not documented. Some of register names |
240 | * are guessed by comparing the register offsets with the DP83TD510E. |
241 | */ |
242 | |
243 | /* Force master link down */ |
244 | ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, |
245 | DP83TG720S_TDR_MASTER_LINK_DOWN, val: 0x0400); |
246 | if (ret) |
247 | return ret; |
248 | |
249 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG2, |
250 | val: 0xa008); |
251 | if (ret) |
252 | return ret; |
253 | |
254 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG3, |
255 | val: 0x0928); |
256 | if (ret) |
257 | return ret; |
258 | |
259 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG4, |
260 | val: 0x0004); |
261 | if (ret) |
262 | return ret; |
263 | |
264 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_UNKNOWN_0405, |
265 | val: 0x6400); |
266 | if (ret) |
267 | return ret; |
268 | |
269 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_UNKNOWN_083F, |
270 | val: 0x3003); |
271 | if (ret) |
272 | return ret; |
273 | |
274 | /* Start the TDR */ |
275 | ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG, |
276 | DP83TG720S_TDR_START); |
277 | if (ret) |
278 | return ret; |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | /** |
284 | * dp83tg720_cable_test_get_status - Get the status of the cable test for the |
285 | * DP83TG720 PHY. |
286 | * @phydev: Pointer to the phy_device structure. |
287 | * @finished: Pointer to a boolean that indicates whether the test is finished. |
288 | * |
289 | * The function sets the @finished flag to true if the test is complete. |
290 | * |
291 | * Returns: 0 on success or a negative error code on failure. |
292 | */ |
293 | static int dp83tg720_cable_test_get_status(struct phy_device *phydev, |
294 | bool *finished) |
295 | { |
296 | int ret, stat; |
297 | |
298 | *finished = false; |
299 | |
300 | /* Read the TDR status */ |
301 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG); |
302 | if (ret < 0) |
303 | return ret; |
304 | |
305 | /* Check if the TDR test is done */ |
306 | if (!(ret & DP83TG720S_TDR_DONE)) |
307 | return 0; |
308 | |
309 | /* Check for TDR test failure */ |
310 | if (!(ret & DP83TG720S_TDR_FAIL)) { |
311 | int location; |
312 | |
313 | /* Read fault status */ |
314 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, |
315 | DP83TG720S_TDR_FAULT_STATUS); |
316 | if (ret < 0) |
317 | return ret; |
318 | |
319 | /* Get fault type */ |
320 | stat = oa_1000bt1_get_ethtool_cable_result_code(reg_value: ret); |
321 | |
322 | /* Determine fault location */ |
323 | location = oa_1000bt1_get_tdr_distance(reg_value: ret); |
324 | if (location > 0) |
325 | ethnl_cable_test_fault_length(phydev, |
326 | pair: ETHTOOL_A_CABLE_PAIR_A, |
327 | cm: location); |
328 | } else { |
329 | /* Active link partner or other issues */ |
330 | stat = ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; |
331 | } |
332 | |
333 | *finished = true; |
334 | |
335 | ethnl_cable_test_result(phydev, pair: ETHTOOL_A_CABLE_PAIR_A, result: stat); |
336 | |
337 | /* save the current stats before resetting the PHY */ |
338 | ret = dp83tg720_update_stats(phydev); |
339 | if (ret) |
340 | return ret; |
341 | |
342 | return phy_init_hw(phydev); |
343 | } |
344 | |
345 | static int dp83tg720_config_aneg(struct phy_device *phydev) |
346 | { |
347 | int ret; |
348 | |
349 | /* Autoneg is not supported and this PHY supports only one speed. |
350 | * We need to care only about master/slave configuration if it was |
351 | * changed by user. |
352 | */ |
353 | ret = genphy_c45_pma_baset1_setup_master_slave(phydev); |
354 | if (ret) |
355 | return ret; |
356 | |
357 | /* Re-read role configuration to make changes visible even if |
358 | * the link is in administrative down state. |
359 | */ |
360 | return genphy_c45_pma_baset1_read_master_slave(phydev); |
361 | } |
362 | |
363 | static int dp83tg720_read_status(struct phy_device *phydev) |
364 | { |
365 | u16 phy_sts; |
366 | int ret; |
367 | |
368 | phydev->pause = 0; |
369 | phydev->asym_pause = 0; |
370 | |
371 | /* Most of Clause 45 registers are not present, so we can't use |
372 | * genphy_c45_read_status() here. |
373 | */ |
374 | phy_sts = phy_read(phydev, DP83TG720S_MII_REG_10); |
375 | phydev->link = !!(phy_sts & DP83TG720S_LINK_STATUS); |
376 | if (!phydev->link) { |
377 | /* save the current stats before resetting the PHY */ |
378 | ret = dp83tg720_update_stats(phydev); |
379 | if (ret) |
380 | return ret; |
381 | |
382 | /* According to the "DP83TC81x, DP83TG72x Software |
383 | * Implementation Guide", the PHY needs to be reset after a |
384 | * link loss or if no link is created after at least 100ms. |
385 | * |
386 | * Currently we are polling with the PHY_STATE_TIME (1000ms) |
387 | * interval, which is still enough for not automotive use cases. |
388 | */ |
389 | ret = phy_init_hw(phydev); |
390 | if (ret) |
391 | return ret; |
392 | |
393 | /* Sleep 600ms for PHY stabilization post-reset. |
394 | * Empirically chosen value (not documented). |
395 | * Helps reduce reset bounces with link partners having similar |
396 | * issues. |
397 | */ |
398 | msleep(msecs: 600); |
399 | |
400 | /* After HW reset we need to restore master/slave configuration. |
401 | * genphy_c45_pma_baset1_read_master_slave() call will be done |
402 | * by the dp83tg720_config_aneg() function. |
403 | */ |
404 | ret = dp83tg720_config_aneg(phydev); |
405 | if (ret) |
406 | return ret; |
407 | |
408 | phydev->speed = SPEED_UNKNOWN; |
409 | phydev->duplex = DUPLEX_UNKNOWN; |
410 | } else { |
411 | /* PMA/PMD control 1 register (Register 1.0) is present, but it |
412 | * doesn't contain the link speed information. |
413 | * So genphy_c45_read_pma() can't be used here. |
414 | */ |
415 | ret = genphy_c45_pma_baset1_read_master_slave(phydev); |
416 | if (ret) |
417 | return ret; |
418 | |
419 | phydev->duplex = DUPLEX_FULL; |
420 | phydev->speed = SPEED_1000; |
421 | } |
422 | |
423 | return 0; |
424 | } |
425 | |
426 | static int dp83tg720_get_sqi(struct phy_device *phydev) |
427 | { |
428 | int ret; |
429 | |
430 | if (!phydev->link) |
431 | return 0; |
432 | |
433 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_SQI_REG_1); |
434 | if (ret < 0) |
435 | return ret; |
436 | |
437 | return FIELD_GET(DP83TG720S_SQI_OUT, ret); |
438 | } |
439 | |
440 | static int dp83tg720_get_sqi_max(struct phy_device *phydev) |
441 | { |
442 | return DP83TG720_SQI_MAX; |
443 | } |
444 | |
445 | static int dp83tg720_config_rgmii_delay(struct phy_device *phydev) |
446 | { |
447 | u16 rgmii_delay_mask; |
448 | u16 rgmii_delay = 0; |
449 | |
450 | switch (phydev->interface) { |
451 | case PHY_INTERFACE_MODE_RGMII: |
452 | rgmii_delay = 0; |
453 | break; |
454 | case PHY_INTERFACE_MODE_RGMII_ID: |
455 | rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL | |
456 | DP83TG720S_RGMII_TX_CLK_SEL; |
457 | break; |
458 | case PHY_INTERFACE_MODE_RGMII_RXID: |
459 | rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL; |
460 | break; |
461 | case PHY_INTERFACE_MODE_RGMII_TXID: |
462 | rgmii_delay = DP83TG720S_RGMII_TX_CLK_SEL; |
463 | break; |
464 | default: |
465 | return 0; |
466 | } |
467 | |
468 | rgmii_delay_mask = DP83TG720S_RGMII_RX_CLK_SEL | |
469 | DP83TG720S_RGMII_TX_CLK_SEL; |
470 | |
471 | return phy_modify_mmd(phydev, MDIO_MMD_VEND2, |
472 | DP83TG720S_RGMII_DELAY_CTRL, mask: rgmii_delay_mask, |
473 | set: rgmii_delay); |
474 | } |
475 | |
476 | static int dp83tg720_config_init(struct phy_device *phydev) |
477 | { |
478 | int ret; |
479 | |
480 | /* Software Restart is not enough to recover from a link failure. |
481 | * Using Hardware Reset instead. |
482 | */ |
483 | ret = phy_write(phydev, DP83TG720S_PHY_RESET, DP83TG720S_HW_RESET); |
484 | if (ret) |
485 | return ret; |
486 | |
487 | /* Wait until MDC can be used again. |
488 | * The wait value of one 1ms is documented in "DP83TG720S-Q1 1000BASE-T1 |
489 | * Automotive Ethernet PHY with SGMII and RGMII" datasheet. |
490 | */ |
491 | usleep_range(min: 1000, max: 2000); |
492 | |
493 | if (phy_interface_is_rgmii(phydev)) { |
494 | ret = dp83tg720_config_rgmii_delay(phydev); |
495 | if (ret) |
496 | return ret; |
497 | } |
498 | |
499 | /* In case the PHY is bootstrapped in managed mode, we need to |
500 | * wake it. |
501 | */ |
502 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_LPS_CFG3, |
503 | DP83TG720S_LPS_CFG3_PWR_MODE_0); |
504 | if (ret) |
505 | return ret; |
506 | |
507 | /* Make role configuration visible for ethtool on init and after |
508 | * rest. |
509 | */ |
510 | return genphy_c45_pma_baset1_read_master_slave(phydev); |
511 | } |
512 | |
513 | static int dp83tg720_probe(struct phy_device *phydev) |
514 | { |
515 | struct device *dev = &phydev->mdio.dev; |
516 | struct dp83tg720_priv *priv; |
517 | |
518 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
519 | if (!priv) |
520 | return -ENOMEM; |
521 | |
522 | phydev->priv = priv; |
523 | |
524 | return 0; |
525 | } |
526 | |
527 | /** |
528 | * dp83tg720_get_next_update_time - Determine the next update time for PHY |
529 | * state |
530 | * @phydev: Pointer to the phy_device structure |
531 | * |
532 | * This function addresses a limitation of the DP83TG720 PHY, which cannot |
533 | * reliably detect or report a stable link state. To recover from such |
534 | * scenarios, the PHY must be periodically reset when the link is down. However, |
535 | * if the link partner also runs Linux with the same driver, synchronized reset |
536 | * intervals can lead to a deadlock where the link never establishes due to |
537 | * simultaneous resets on both sides. |
538 | * |
539 | * To avoid this, the function implements randomized polling intervals when the |
540 | * link is down. It ensures that reset intervals are desynchronized by |
541 | * introducing a random delay between a configured minimum and maximum range. |
542 | * When the link is up, a fixed polling interval is used to minimize overhead. |
543 | * |
544 | * This mechanism guarantees that the link will reestablish within 10 seconds |
545 | * in the worst-case scenario. |
546 | * |
547 | * Return: Time (in jiffies) until the next update event for the PHY state |
548 | * machine. |
549 | */ |
550 | static unsigned int dp83tg720_get_next_update_time(struct phy_device *phydev) |
551 | { |
552 | unsigned int next_time_jiffies; |
553 | |
554 | if (phydev->link) { |
555 | /* When the link is up, use a fixed 1000ms interval |
556 | * (in jiffies) |
557 | */ |
558 | next_time_jiffies = |
559 | msecs_to_jiffies(DP83TG720S_POLL_ACTIVE_LINK); |
560 | } else { |
561 | unsigned int min_jiffies, max_jiffies, rand_jiffies; |
562 | |
563 | /* When the link is down, randomize interval between min/max |
564 | * (in jiffies) |
565 | */ |
566 | min_jiffies = msecs_to_jiffies(DP83TG720S_POLL_NO_LINK_MIN); |
567 | max_jiffies = msecs_to_jiffies(DP83TG720S_POLL_NO_LINK_MAX); |
568 | |
569 | rand_jiffies = min_jiffies + |
570 | get_random_u32_below(ceil: max_jiffies - min_jiffies + 1); |
571 | next_time_jiffies = rand_jiffies; |
572 | } |
573 | |
574 | /* Ensure the polling time is at least one jiffy */ |
575 | return max(next_time_jiffies, 1U); |
576 | } |
577 | |
578 | static struct phy_driver dp83tg720_driver[] = { |
579 | { |
580 | PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID), |
581 | .name = "TI DP83TG720S", |
582 | |
583 | .flags = PHY_POLL_CABLE_TEST, |
584 | .probe = dp83tg720_probe, |
585 | .config_aneg = dp83tg720_config_aneg, |
586 | .read_status = dp83tg720_read_status, |
587 | .get_features = genphy_c45_pma_read_ext_abilities, |
588 | .config_init = dp83tg720_config_init, |
589 | .get_sqi = dp83tg720_get_sqi, |
590 | .get_sqi_max = dp83tg720_get_sqi_max, |
591 | .cable_test_start = dp83tg720_cable_test_start, |
592 | .cable_test_get_status = dp83tg720_cable_test_get_status, |
593 | .get_link_stats = dp83tg720_get_link_stats, |
594 | .get_phy_stats = dp83tg720_get_phy_stats, |
595 | .update_stats = dp83tg720_update_stats, |
596 | .get_next_update_time = dp83tg720_get_next_update_time, |
597 | |
598 | .suspend = genphy_suspend, |
599 | .resume = genphy_resume, |
600 | } }; |
601 | module_phy_driver(dp83tg720_driver); |
602 | |
603 | static const struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { |
604 | { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) }, |
605 | { } |
606 | }; |
607 | MODULE_DEVICE_TABLE(mdio, dp83tg720_tbl); |
608 | |
609 | MODULE_DESCRIPTION("Texas Instruments DP83TG720S PHY driver"); |
610 | MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>"); |
611 | MODULE_LICENSE("GPL"); |
612 |
Definitions
- dp83tg720_stats
- dp83tg720_priv
- dp83tg720_update_stats
- dp83tg720_get_link_stats
- dp83tg720_get_phy_stats
- dp83tg720_cable_test_start
- dp83tg720_cable_test_get_status
- dp83tg720_config_aneg
- dp83tg720_read_status
- dp83tg720_get_sqi
- dp83tg720_get_sqi_max
- dp83tg720_config_rgmii_delay
- dp83tg720_config_init
- dp83tg720_probe
- dp83tg720_get_next_update_time
- dp83tg720_driver
Improve your Profiling and Debugging skills
Find out more