Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / phy / marvell-88q2xxx.c
blob5107f58338aff4ed6cfea4d91e37282d9bb60ba5
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver
5 * Derived from Marvell Q222x API
7 * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
8 */
9 #include <linux/ethtool_netlink.h>
10 #include <linux/marvell_phy.h>
11 #include <linux/phy.h>
12 #include <linux/hwmon.h>
14 #define PHY_ID_88Q2220_REVB0 (MARVELL_PHY_ID_88Q2220 | 0x1)
15 #define PHY_ID_88Q2220_REVB1 (MARVELL_PHY_ID_88Q2220 | 0x2)
16 #define PHY_ID_88Q2220_REVB2 (MARVELL_PHY_ID_88Q2220 | 0x3)
18 #define MDIO_MMD_AN_MV_STAT 32769
19 #define MDIO_MMD_AN_MV_STAT_ANEG 0x0100
20 #define MDIO_MMD_AN_MV_STAT_LOCAL_RX 0x1000
21 #define MDIO_MMD_AN_MV_STAT_REMOTE_RX 0x2000
22 #define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER 0x4000
23 #define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT 0x8000
25 #define MDIO_MMD_AN_MV_STAT2 32794
26 #define MDIO_MMD_AN_MV_STAT2_AN_RESOLVED 0x0800
27 #define MDIO_MMD_AN_MV_STAT2_100BT1 0x2000
28 #define MDIO_MMD_AN_MV_STAT2_1000BT1 0x4000
30 #define MDIO_MMD_PCS_MV_INT_EN 32784
31 #define MDIO_MMD_PCS_MV_INT_EN_LINK_UP 0x0040
32 #define MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN 0x0080
33 #define MDIO_MMD_PCS_MV_INT_EN_100BT1 0x1000
35 #define MDIO_MMD_PCS_MV_GPIO_INT_STAT 32785
36 #define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP 0x0040
37 #define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN 0x0080
38 #define MDIO_MMD_PCS_MV_GPIO_INT_STAT_100BT1_GEN 0x1000
40 #define MDIO_MMD_PCS_MV_GPIO_INT_CTRL 32787
41 #define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS 0x0800
43 #define MDIO_MMD_PCS_MV_TEMP_SENSOR1 32833
44 #define MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT 0x0001
45 #define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT 0x0040
46 #define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT_EN 0x0080
48 #define MDIO_MMD_PCS_MV_TEMP_SENSOR2 32834
49 #define MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK 0xc000
51 #define MDIO_MMD_PCS_MV_TEMP_SENSOR3 32835
52 #define MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK 0xff00
53 #define MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK 0x00ff
55 #define MDIO_MMD_PCS_MV_100BT1_STAT1 33032
56 #define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff
57 #define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100
58 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK 0x0200
59 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX 0x1000
60 #define MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX 0x2000
61 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_MASTER 0x4000
63 #define MDIO_MMD_PCS_MV_100BT1_STAT2 33033
64 #define MDIO_MMD_PCS_MV_100BT1_STAT2_JABBER 0x0001
65 #define MDIO_MMD_PCS_MV_100BT1_STAT2_POL 0x0002
66 #define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK 0x0004
67 #define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE 0x0008
69 #define MDIO_MMD_PCS_MV_100BT1_INT_EN 33042
70 #define MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT 0x0400
72 #define MDIO_MMD_PCS_MV_COPPER_INT_STAT 33043
73 #define MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT 0x0400
75 #define MDIO_MMD_PCS_MV_RX_STAT 33328
77 #define MDIO_MMD_PCS_MV_TDR_RESET 65226
78 #define MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST 0x1000
80 #define MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE 65241
82 #define MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE 65242
84 #define MDIO_MMD_PCS_MV_TDR_STATUS 65245
85 #define MDIO_MMD_PCS_MV_TDR_STATUS_MASK 0x0003
86 #define MDIO_MMD_PCS_MV_TDR_STATUS_OFF 0x0001
87 #define MDIO_MMD_PCS_MV_TDR_STATUS_ON 0x0002
88 #define MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK 0xff00
89 #define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK 0x00f0
90 #define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT 0x0030
91 #define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN 0x00e0
92 #define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK 0x0070
93 #define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_IN_PROGR 0x0080
94 #define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_NOISE 0x0050
96 #define MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF 65246
98 struct mmd_val {
99 int devad;
100 u32 regnum;
101 u16 val;
104 static const struct mmd_val mv88q2110_init_seq0[] = {
105 { MDIO_MMD_PCS, 0xffe4, 0x07b5 },
106 { MDIO_MMD_PCS, 0xffe4, 0x06b6 },
109 static const struct mmd_val mv88q2110_init_seq1[] = {
110 { MDIO_MMD_PCS, 0xffde, 0x402f },
111 { MDIO_MMD_PCS, 0xfe34, 0x4040 },
112 { MDIO_MMD_PCS, 0xfe2a, 0x3c1d },
113 { MDIO_MMD_PCS, 0xfe34, 0x0040 },
114 { MDIO_MMD_AN, 0x8032, 0x0064 },
115 { MDIO_MMD_AN, 0x8031, 0x0a01 },
116 { MDIO_MMD_AN, 0x8031, 0x0c01 },
117 { MDIO_MMD_PCS, 0xffdb, 0x0010 },
120 static const struct mmd_val mv88q222x_revb0_init_seq0[] = {
121 { MDIO_MMD_PCS, 0x8033, 0x6801 },
122 { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
123 { MDIO_MMD_PMAPMD, MDIO_CTRL1,
124 MDIO_CTRL1_LPOWER | MDIO_PMA_CTRL1_SPEED1000 },
125 { MDIO_MMD_PCS, 0xfe1b, 0x48 },
126 { MDIO_MMD_PCS, 0xffe4, 0x6b6 },
127 { MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0 },
128 { MDIO_MMD_PCS, MDIO_CTRL1, 0x0 },
131 static const struct mmd_val mv88q222x_revb0_init_seq1[] = {
132 { MDIO_MMD_PCS, 0xfe79, 0x0 },
133 { MDIO_MMD_PCS, 0xfe07, 0x125a },
134 { MDIO_MMD_PCS, 0xfe09, 0x1288 },
135 { MDIO_MMD_PCS, 0xfe08, 0x2588 },
136 { MDIO_MMD_PCS, 0xfe11, 0x1105 },
137 { MDIO_MMD_PCS, 0xfe72, 0x042c },
138 { MDIO_MMD_PCS, 0xfbba, 0xcb2 },
139 { MDIO_MMD_PCS, 0xfbbb, 0xc4a },
140 { MDIO_MMD_AN, 0x8032, 0x2020 },
141 { MDIO_MMD_AN, 0x8031, 0xa28 },
142 { MDIO_MMD_AN, 0x8031, 0xc28 },
143 { MDIO_MMD_PCS, 0xffdb, 0xfc10 },
144 { MDIO_MMD_PCS, 0xfe1b, 0x58 },
145 { MDIO_MMD_PCS, 0xfe79, 0x4 },
146 { MDIO_MMD_PCS, 0xfe5f, 0xe8 },
147 { MDIO_MMD_PCS, 0xfe05, 0x755c },
150 static const struct mmd_val mv88q222x_revb1_init_seq0[] = {
151 { MDIO_MMD_PCS, 0xffe4, 0x0007 },
152 { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
153 { MDIO_MMD_PCS, 0xffe3, 0x7000 },
154 { MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0840 },
157 static const struct mmd_val mv88q222x_revb2_init_seq0[] = {
158 { MDIO_MMD_PCS, 0xffe4, 0x0007 },
159 { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
160 { MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0840 },
163 static const struct mmd_val mv88q222x_revb1_revb2_init_seq1[] = {
164 { MDIO_MMD_PCS, 0xfe07, 0x125a },
165 { MDIO_MMD_PCS, 0xfe09, 0x1288 },
166 { MDIO_MMD_PCS, 0xfe08, 0x2588 },
167 { MDIO_MMD_PCS, 0xfe72, 0x042c },
168 { MDIO_MMD_PCS, 0xffe4, 0x0071 },
169 { MDIO_MMD_PCS, 0xffe4, 0x0001 },
170 { MDIO_MMD_PCS, 0xfe1b, 0x0048 },
171 { MDIO_MMD_PMAPMD, 0x0000, 0x0000 },
172 { MDIO_MMD_PCS, 0x0000, 0x0000 },
173 { MDIO_MMD_PCS, 0xffdb, 0xfc10 },
174 { MDIO_MMD_PCS, 0xfe1b, 0x58 },
175 { MDIO_MMD_PCS, 0xfcad, 0x030c },
176 { MDIO_MMD_PCS, 0x8032, 0x6001 },
177 { MDIO_MMD_PCS, 0xfdff, 0x05a5 },
178 { MDIO_MMD_PCS, 0xfdec, 0xdbaf },
179 { MDIO_MMD_PCS, 0xfcab, 0x1054 },
180 { MDIO_MMD_PCS, 0xfcac, 0x1483 },
181 { MDIO_MMD_PCS, 0x8033, 0xc801 },
182 { MDIO_MMD_AN, 0x8032, 0x2020 },
183 { MDIO_MMD_AN, 0x8031, 0xa28 },
184 { MDIO_MMD_AN, 0x8031, 0xc28 },
185 { MDIO_MMD_PCS, 0xfbba, 0x0cb2 },
186 { MDIO_MMD_PCS, 0xfbbb, 0x0c4a },
187 { MDIO_MMD_PCS, 0xfe5f, 0xe8 },
188 { MDIO_MMD_PCS, 0xfe05, 0x755c },
189 { MDIO_MMD_PCS, 0xfa20, 0x002a },
190 { MDIO_MMD_PCS, 0xfe11, 0x1105 },
193 static int mv88q2xxx_write_mmd_vals(struct phy_device *phydev,
194 const struct mmd_val *vals, size_t len)
196 int ret;
198 for (; len; vals++, len--) {
199 ret = phy_write_mmd(phydev, vals->devad, vals->regnum,
200 vals->val);
201 if (ret < 0)
202 return ret;
205 return 0;
208 static int mv88q2xxx_soft_reset(struct phy_device *phydev)
210 int ret;
211 int val;
213 /* Enable RESET of DCL */
214 if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) {
215 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48);
216 if (ret < 0)
217 return ret;
220 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL,
221 MDIO_PCS_1000BT1_CTRL_RESET);
222 if (ret < 0)
223 return ret;
225 ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
226 MDIO_PCS_1000BT1_CTRL, val,
227 !(val & MDIO_PCS_1000BT1_CTRL_RESET),
228 50000, 600000, true);
229 if (ret < 0)
230 return ret;
232 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc);
233 if (ret < 0)
234 return ret;
236 /* Disable RESET of DCL */
237 if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000)
238 return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58);
240 return 0;
243 static int mv88q2xxx_read_link_gbit(struct phy_device *phydev)
245 int ret;
246 bool link = false;
248 /* Read vendor specific Auto-Negotiation status register to get local
249 * and remote receiver status according to software initialization
250 * guide. However, when not in polling mode the local and remote
251 * receiver status are not evaluated due to the Marvell 88Q2xxx APIs.
253 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
254 if (ret < 0) {
255 return ret;
256 } else if (((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) &&
257 (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) ||
258 !phy_polling_mode(phydev)) {
259 /* The link state is latched low so that momentary link
260 * drops can be detected. Do not double-read the status
261 * in polling mode to detect such short link drops except
262 * the link was already down.
264 if (!phy_polling_mode(phydev) || !phydev->link) {
265 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
266 MDIO_PCS_1000BT1_STAT);
267 if (ret < 0)
268 return ret;
269 else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
270 link = true;
273 if (!link) {
274 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
275 MDIO_PCS_1000BT1_STAT);
276 if (ret < 0)
277 return ret;
278 else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
279 link = true;
283 phydev->link = link;
285 return 0;
288 static int mv88q2xxx_read_link_100m(struct phy_device *phydev)
290 int ret;
292 /* The link state is latched low so that momentary link
293 * drops can be detected. Do not double-read the status
294 * in polling mode to detect such short link drops except
295 * the link was already down. In case we are not polling,
296 * we always read the realtime status.
298 if (!phy_polling_mode(phydev)) {
299 phydev->link = false;
300 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
301 MDIO_MMD_PCS_MV_100BT1_STAT2);
302 if (ret < 0)
303 return ret;
305 if (ret & MDIO_MMD_PCS_MV_100BT1_STAT2_LINK)
306 phydev->link = true;
308 return 0;
309 } else if (!phydev->link) {
310 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
311 MDIO_MMD_PCS_MV_100BT1_STAT1);
312 if (ret < 0)
313 return ret;
314 else if (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK)
315 goto out;
318 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
319 if (ret < 0)
320 return ret;
322 out:
323 /* Check if we have link and if the remote and local receiver are ok */
324 if ((ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK) &&
325 (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX) &&
326 (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX))
327 phydev->link = true;
328 else
329 phydev->link = false;
331 return 0;
334 static int mv88q2xxx_read_link(struct phy_device *phydev)
336 /* The 88Q2XXX PHYs do not have the PMA/PMD status register available,
337 * therefore we need to read the link status from the vendor specific
338 * registers depending on the speed.
341 if (phydev->speed == SPEED_1000)
342 return mv88q2xxx_read_link_gbit(phydev);
343 else if (phydev->speed == SPEED_100)
344 return mv88q2xxx_read_link_100m(phydev);
346 phydev->link = false;
347 return 0;
350 static int mv88q2xxx_read_master_slave_state(struct phy_device *phydev)
352 int ret;
354 phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
355 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
356 if (ret < 0)
357 return ret;
359 if (ret & MDIO_MMD_AN_MV_STAT_LOCAL_MASTER)
360 phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
361 else
362 phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
364 return 0;
367 static int mv88q2xxx_read_aneg_speed(struct phy_device *phydev)
369 int ret;
371 phydev->speed = SPEED_UNKNOWN;
372 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT2);
373 if (ret < 0)
374 return ret;
376 if (!(ret & MDIO_MMD_AN_MV_STAT2_AN_RESOLVED))
377 return 0;
379 if (ret & MDIO_MMD_AN_MV_STAT2_100BT1)
380 phydev->speed = SPEED_100;
381 else if (ret & MDIO_MMD_AN_MV_STAT2_1000BT1)
382 phydev->speed = SPEED_1000;
384 return 0;
387 static int mv88q2xxx_read_status(struct phy_device *phydev)
389 int ret;
391 if (phydev->autoneg == AUTONEG_ENABLE) {
392 /* We have to get the negotiated speed first, otherwise we are
393 * not able to read the link.
395 ret = mv88q2xxx_read_aneg_speed(phydev);
396 if (ret < 0)
397 return ret;
399 ret = mv88q2xxx_read_link(phydev);
400 if (ret < 0)
401 return ret;
403 ret = genphy_c45_read_lpa(phydev);
404 if (ret < 0)
405 return ret;
407 ret = genphy_c45_baset1_read_status(phydev);
408 if (ret < 0)
409 return ret;
411 ret = mv88q2xxx_read_master_slave_state(phydev);
412 if (ret < 0)
413 return ret;
415 phy_resolve_aneg_linkmode(phydev);
417 return 0;
420 ret = mv88q2xxx_read_link(phydev);
421 if (ret < 0)
422 return ret;
424 return genphy_c45_read_pma(phydev);
427 static int mv88q2xxx_get_features(struct phy_device *phydev)
429 int ret;
431 ret = genphy_c45_pma_read_abilities(phydev);
432 if (ret)
433 return ret;
435 /* We need to read the baset1 extended abilities manually because the
436 * PHY does not signalize it has the extended abilities register
437 * available.
439 ret = genphy_c45_pma_baset1_read_abilities(phydev);
440 if (ret)
441 return ret;
443 return 0;
446 static int mv88q2xxx_config_aneg(struct phy_device *phydev)
448 int ret;
450 ret = genphy_c45_config_aneg(phydev);
451 if (ret)
452 return ret;
454 return phydev->drv->soft_reset(phydev);
457 static int mv88q2xxx_config_init(struct phy_device *phydev)
459 /* The 88Q2XXX PHYs do have the extended ability register available, but
460 * register MDIO_PMA_EXTABLE where they should signalize it does not
461 * work according to specification. Therefore, we force it here.
463 phydev->pma_extable = MDIO_PMA_EXTABLE_BT1;
465 /* Configure interrupt with default settings, output is driven low for
466 * active interrupt and high for inactive.
468 if (phy_interrupt_is_valid(phydev))
469 return phy_set_bits_mmd(phydev, MDIO_MMD_PCS,
470 MDIO_MMD_PCS_MV_GPIO_INT_CTRL,
471 MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS);
473 return 0;
476 static int mv88q2xxx_get_sqi(struct phy_device *phydev)
478 int ret;
480 if (phydev->speed == SPEED_100) {
481 /* Read the SQI from the vendor specific receiver status
482 * register
484 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
485 MDIO_MMD_PCS_MV_RX_STAT);
486 if (ret < 0)
487 return ret;
489 ret = ret >> 12;
490 } else {
491 /* Read from vendor specific registers, they are not documented
492 * but can be found in the Software Initialization Guide. Only
493 * revisions >= A0 are supported.
495 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 0xfc5d, 0xff, 0xac);
496 if (ret < 0)
497 return ret;
499 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0xfc88);
500 if (ret < 0)
501 return ret;
504 return ret & 0x0f;
507 static int mv88q2xxx_get_sqi_max(struct phy_device *phydev)
509 return 15;
512 static int mv88q2xxx_config_intr(struct phy_device *phydev)
514 int ret;
516 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
517 /* Enable interrupts for 1000BASE-T1 link up and down events
518 * and enable general interrupts for 100BASE-T1.
520 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
521 MDIO_MMD_PCS_MV_INT_EN,
522 MDIO_MMD_PCS_MV_INT_EN_LINK_UP |
523 MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN |
524 MDIO_MMD_PCS_MV_INT_EN_100BT1);
525 if (ret < 0)
526 return ret;
528 /* Enable interrupts for 100BASE-T1 link events */
529 return phy_write_mmd(phydev, MDIO_MMD_PCS,
530 MDIO_MMD_PCS_MV_100BT1_INT_EN,
531 MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT);
532 } else {
533 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
534 MDIO_MMD_PCS_MV_INT_EN, 0);
535 if (ret < 0)
536 return ret;
538 return phy_write_mmd(phydev, MDIO_MMD_PCS,
539 MDIO_MMD_PCS_MV_100BT1_INT_EN, 0);
543 static irqreturn_t mv88q2xxx_handle_interrupt(struct phy_device *phydev)
545 bool trigger_machine = false;
546 int irq;
548 /* Before we can acknowledge the 100BT1 general interrupt, that is in
549 * the 1000BT1 interrupt status register, we have to acknowledge any
550 * interrupts that are related to it. Therefore we read first the 100BT1
551 * interrupt status register, followed by reading the 1000BT1 interrupt
552 * status register.
555 irq = phy_read_mmd(phydev, MDIO_MMD_PCS,
556 MDIO_MMD_PCS_MV_COPPER_INT_STAT);
557 if (irq < 0) {
558 phy_error(phydev);
559 return IRQ_NONE;
562 /* Check link status for 100BT1 */
563 if (irq & MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT)
564 trigger_machine = true;
566 irq = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_GPIO_INT_STAT);
567 if (irq < 0) {
568 phy_error(phydev);
569 return IRQ_NONE;
572 /* Check link status for 1000BT1 */
573 if ((irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP) ||
574 (irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN))
575 trigger_machine = true;
577 if (!trigger_machine)
578 return IRQ_NONE;
580 phy_trigger_machine(phydev);
582 return IRQ_HANDLED;
585 static int mv88q2xxx_suspend(struct phy_device *phydev)
587 int ret;
589 /* Disable PHY interrupts */
590 if (phy_interrupt_is_valid(phydev)) {
591 phydev->interrupts = PHY_INTERRUPT_DISABLED;
592 ret = mv88q2xxx_config_intr(phydev);
593 if (ret)
594 return ret;
597 return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
598 MDIO_CTRL1_LPOWER);
601 static int mv88q2xxx_resume(struct phy_device *phydev)
603 int ret;
605 /* Enable PHY interrupts */
606 if (phy_interrupt_is_valid(phydev)) {
607 phydev->interrupts = PHY_INTERRUPT_ENABLED;
608 ret = mv88q2xxx_config_intr(phydev);
609 if (ret)
610 return ret;
613 return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
614 MDIO_CTRL1_LPOWER);
617 #if IS_ENABLED(CONFIG_HWMON)
618 static const struct hwmon_channel_info * const mv88q2xxx_hwmon_info[] = {
619 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_ALARM),
620 NULL
623 static umode_t mv88q2xxx_hwmon_is_visible(const void *data,
624 enum hwmon_sensor_types type,
625 u32 attr, int channel)
627 switch (attr) {
628 case hwmon_temp_input:
629 return 0444;
630 case hwmon_temp_max:
631 return 0644;
632 case hwmon_temp_alarm:
633 return 0444;
634 default:
635 return 0;
639 static int mv88q2xxx_hwmon_read(struct device *dev,
640 enum hwmon_sensor_types type,
641 u32 attr, int channel, long *val)
643 struct phy_device *phydev = dev_get_drvdata(dev);
644 int ret;
646 switch (attr) {
647 case hwmon_temp_input:
648 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
649 MDIO_MMD_PCS_MV_TEMP_SENSOR3);
650 if (ret < 0)
651 return ret;
653 ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK, ret);
654 *val = (ret - 75) * 1000;
655 return 0;
656 case hwmon_temp_max:
657 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
658 MDIO_MMD_PCS_MV_TEMP_SENSOR3);
659 if (ret < 0)
660 return ret;
662 ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
663 ret);
664 *val = (ret - 75) * 1000;
665 return 0;
666 case hwmon_temp_alarm:
667 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
668 MDIO_MMD_PCS_MV_TEMP_SENSOR1);
669 if (ret < 0)
670 return ret;
672 *val = !!(ret & MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT);
673 return 0;
674 default:
675 return -EOPNOTSUPP;
679 static int mv88q2xxx_hwmon_write(struct device *dev,
680 enum hwmon_sensor_types type, u32 attr,
681 int channel, long val)
683 struct phy_device *phydev = dev_get_drvdata(dev);
685 switch (attr) {
686 case hwmon_temp_max:
687 clamp_val(val, -75000, 180000);
688 val = (val / 1000) + 75;
689 val = FIELD_PREP(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
690 val);
691 return phy_modify_mmd(phydev, MDIO_MMD_PCS,
692 MDIO_MMD_PCS_MV_TEMP_SENSOR3,
693 MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
694 val);
695 default:
696 return -EOPNOTSUPP;
700 static const struct hwmon_ops mv88q2xxx_hwmon_hwmon_ops = {
701 .is_visible = mv88q2xxx_hwmon_is_visible,
702 .read = mv88q2xxx_hwmon_read,
703 .write = mv88q2xxx_hwmon_write,
706 static const struct hwmon_chip_info mv88q2xxx_hwmon_chip_info = {
707 .ops = &mv88q2xxx_hwmon_hwmon_ops,
708 .info = mv88q2xxx_hwmon_info,
711 static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
713 struct device *dev = &phydev->mdio.dev;
714 struct device *hwmon;
715 char *hwmon_name;
716 int ret;
718 /* Enable temperature sense */
719 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TEMP_SENSOR2,
720 MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK, 0);
721 if (ret < 0)
722 return ret;
724 hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev));
725 if (IS_ERR(hwmon_name))
726 return PTR_ERR(hwmon_name);
728 hwmon = devm_hwmon_device_register_with_info(dev,
729 hwmon_name,
730 phydev,
731 &mv88q2xxx_hwmon_chip_info,
732 NULL);
734 return PTR_ERR_OR_ZERO(hwmon);
737 #else
738 static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
740 return 0;
742 #endif
744 static int mv88q2xxx_probe(struct phy_device *phydev)
746 return mv88q2xxx_hwmon_probe(phydev);
749 static int mv88q2110_config_init(struct phy_device *phydev)
751 int ret;
753 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq0,
754 ARRAY_SIZE(mv88q2110_init_seq0));
755 if (ret < 0)
756 return ret;
758 usleep_range(5000, 10000);
760 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq1,
761 ARRAY_SIZE(mv88q2110_init_seq1));
762 if (ret < 0)
763 return ret;
765 return mv88q2xxx_config_init(phydev);
768 static int mv88q222x_revb0_config_init(struct phy_device *phydev)
770 int ret;
772 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq0,
773 ARRAY_SIZE(mv88q222x_revb0_init_seq0));
774 if (ret < 0)
775 return ret;
777 usleep_range(5000, 10000);
779 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq1,
780 ARRAY_SIZE(mv88q222x_revb0_init_seq1));
781 if (ret < 0)
782 return ret;
784 return mv88q2xxx_config_init(phydev);
787 static int mv88q222x_revb1_revb2_config_init(struct phy_device *phydev)
789 bool is_rev_b1 = phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] == PHY_ID_88Q2220_REVB1;
790 int ret;
792 if (is_rev_b1)
793 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_init_seq0,
794 ARRAY_SIZE(mv88q222x_revb1_init_seq0));
795 else
796 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb2_init_seq0,
797 ARRAY_SIZE(mv88q222x_revb2_init_seq0));
798 if (ret < 0)
799 return ret;
801 usleep_range(3000, 5000);
803 ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_revb2_init_seq1,
804 ARRAY_SIZE(mv88q222x_revb1_revb2_init_seq1));
805 if (ret < 0)
806 return ret;
808 return mv88q2xxx_config_init(phydev);
811 static int mv88q222x_config_init(struct phy_device *phydev)
813 if (phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] == PHY_ID_88Q2220_REVB0)
814 return mv88q222x_revb0_config_init(phydev);
815 else
816 return mv88q222x_revb1_revb2_config_init(phydev);
819 static int mv88q222x_cable_test_start(struct phy_device *phydev)
821 int ret;
823 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
824 MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF, 0x0058);
825 if (ret < 0)
826 return ret;
828 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
829 MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE, 0x00eb);
830 if (ret < 0)
831 return ret;
833 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
834 MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE, 0x010e);
835 if (ret < 0)
836 return ret;
838 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET,
839 0x0d90);
840 if (ret < 0)
841 return ret;
843 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS,
844 MDIO_MMD_PCS_MV_TDR_STATUS_ON);
845 if (ret < 0)
846 return ret;
848 /* According to the Marvell API the test is finished within 500 ms */
849 msleep(500);
851 return 0;
854 static int mv88q222x_cable_test_get_status(struct phy_device *phydev,
855 bool *finished)
857 int ret, status;
858 u32 dist;
860 status = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS);
861 if (status < 0)
862 return status;
864 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET,
865 MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST | 0xd90);
866 if (ret < 0)
867 return ret;
869 /* Test could not be finished */
870 if (FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_MASK, status) !=
871 MDIO_MMD_PCS_MV_TDR_STATUS_OFF)
872 return -ETIMEDOUT;
874 *finished = true;
875 /* Fault length reported in meters, convert to centimeters */
876 dist = FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK, status) * 100;
877 switch (status & MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK) {
878 case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN:
879 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
880 ETHTOOL_A_CABLE_RESULT_CODE_OPEN);
881 ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
882 dist);
883 break;
884 case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT:
885 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
886 ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT);
887 ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
888 dist);
889 break;
890 case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK:
891 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
892 ETHTOOL_A_CABLE_RESULT_CODE_OK);
893 break;
894 default:
895 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
896 ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC);
899 return 0;
902 static struct phy_driver mv88q2xxx_driver[] = {
904 .phy_id = MARVELL_PHY_ID_88Q2110,
905 .phy_id_mask = MARVELL_PHY_ID_MASK,
906 .name = "mv88q2110",
907 .get_features = mv88q2xxx_get_features,
908 .config_aneg = mv88q2xxx_config_aneg,
909 .config_init = mv88q2110_config_init,
910 .read_status = mv88q2xxx_read_status,
911 .soft_reset = mv88q2xxx_soft_reset,
912 .set_loopback = genphy_c45_loopback,
913 .get_sqi = mv88q2xxx_get_sqi,
914 .get_sqi_max = mv88q2xxx_get_sqi_max,
917 .phy_id = MARVELL_PHY_ID_88Q2220,
918 .phy_id_mask = MARVELL_PHY_ID_MASK,
919 .name = "mv88q2220",
920 .flags = PHY_POLL_CABLE_TEST,
921 .probe = mv88q2xxx_probe,
922 .get_features = mv88q2xxx_get_features,
923 .config_aneg = mv88q2xxx_config_aneg,
924 .aneg_done = genphy_c45_aneg_done,
925 .config_init = mv88q222x_config_init,
926 .read_status = mv88q2xxx_read_status,
927 .soft_reset = mv88q2xxx_soft_reset,
928 .config_intr = mv88q2xxx_config_intr,
929 .handle_interrupt = mv88q2xxx_handle_interrupt,
930 .set_loopback = genphy_c45_loopback,
931 .cable_test_start = mv88q222x_cable_test_start,
932 .cable_test_get_status = mv88q222x_cable_test_get_status,
933 .get_sqi = mv88q2xxx_get_sqi,
934 .get_sqi_max = mv88q2xxx_get_sqi_max,
935 .suspend = mv88q2xxx_suspend,
936 .resume = mv88q2xxx_resume,
940 module_phy_driver(mv88q2xxx_driver);
942 static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
943 { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
944 { MARVELL_PHY_ID_88Q2220, MARVELL_PHY_ID_MASK },
945 { /*sentinel*/ }
947 MODULE_DEVICE_TABLE(mdio, mv88q2xxx_tbl);
949 MODULE_DESCRIPTION("Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet PHY driver");
950 MODULE_LICENSE("GPL");