1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver
4 *
5 * Derived from Marvell Q222x API
6 *
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>
13
14#define PHY_ID_88Q2220_REVB0 (MARVELL_PHY_ID_88Q2220 | 0x1)
15
16#define MDIO_MMD_AN_MV_STAT 32769
17#define MDIO_MMD_AN_MV_STAT_ANEG 0x0100
18#define MDIO_MMD_AN_MV_STAT_LOCAL_RX 0x1000
19#define MDIO_MMD_AN_MV_STAT_REMOTE_RX 0x2000
20#define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER 0x4000
21#define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT 0x8000
22
23#define MDIO_MMD_AN_MV_STAT2 32794
24#define MDIO_MMD_AN_MV_STAT2_AN_RESOLVED 0x0800
25#define MDIO_MMD_AN_MV_STAT2_100BT1 0x2000
26#define MDIO_MMD_AN_MV_STAT2_1000BT1 0x4000
27
28#define MDIO_MMD_PCS_MV_INT_EN 32784
29#define MDIO_MMD_PCS_MV_INT_EN_LINK_UP 0x0040
30#define MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN 0x0080
31#define MDIO_MMD_PCS_MV_INT_EN_100BT1 0x1000
32
33#define MDIO_MMD_PCS_MV_GPIO_INT_STAT 32785
34#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP 0x0040
35#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN 0x0080
36#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_100BT1_GEN 0x1000
37
38#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL 32787
39#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS 0x0800
40
41#define MDIO_MMD_PCS_MV_TEMP_SENSOR1 32833
42#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT 0x0001
43#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT 0x0040
44#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT_EN 0x0080
45
46#define MDIO_MMD_PCS_MV_TEMP_SENSOR2 32834
47#define MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK 0xc000
48
49#define MDIO_MMD_PCS_MV_TEMP_SENSOR3 32835
50#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK 0xff00
51#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK 0x00ff
52
53#define MDIO_MMD_PCS_MV_100BT1_STAT1 33032
54#define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff
55#define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100
56#define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK 0x0200
57#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX 0x1000
58#define MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX 0x2000
59#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_MASTER 0x4000
60
61#define MDIO_MMD_PCS_MV_100BT1_STAT2 33033
62#define MDIO_MMD_PCS_MV_100BT1_STAT2_JABBER 0x0001
63#define MDIO_MMD_PCS_MV_100BT1_STAT2_POL 0x0002
64#define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK 0x0004
65#define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE 0x0008
66
67#define MDIO_MMD_PCS_MV_100BT1_INT_EN 33042
68#define MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT 0x0400
69
70#define MDIO_MMD_PCS_MV_COPPER_INT_STAT 33043
71#define MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT 0x0400
72
73#define MDIO_MMD_PCS_MV_RX_STAT 33328
74
75#define MDIO_MMD_PCS_MV_TDR_RESET 65226
76#define MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST 0x1000
77
78#define MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE 65241
79
80#define MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE 65242
81
82#define MDIO_MMD_PCS_MV_TDR_STATUS 65245
83#define MDIO_MMD_PCS_MV_TDR_STATUS_MASK 0x0003
84#define MDIO_MMD_PCS_MV_TDR_STATUS_OFF 0x0001
85#define MDIO_MMD_PCS_MV_TDR_STATUS_ON 0x0002
86#define MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK 0xff00
87#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK 0x00f0
88#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT 0x0030
89#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN 0x00e0
90#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK 0x0070
91#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_IN_PROGR 0x0080
92#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_NOISE 0x0050
93
94#define MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF 65246
95
96struct mmd_val {
97 int devad;
98 u32 regnum;
99 u16 val;
100};
101
102static const struct mmd_val mv88q222x_revb0_init_seq0[] = {
103 { MDIO_MMD_PCS, 0x8033, 0x6801 },
104 { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
105 { MDIO_MMD_PMAPMD, MDIO_CTRL1,
106 MDIO_CTRL1_LPOWER | MDIO_PMA_CTRL1_SPEED1000 },
107 { MDIO_MMD_PCS, 0xfe1b, 0x48 },
108 { MDIO_MMD_PCS, 0xffe4, 0x6b6 },
109 { MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0 },
110 { MDIO_MMD_PCS, MDIO_CTRL1, 0x0 },
111};
112
113static const struct mmd_val mv88q222x_revb0_init_seq1[] = {
114 { MDIO_MMD_PCS, 0xfe79, 0x0 },
115 { MDIO_MMD_PCS, 0xfe07, 0x125a },
116 { MDIO_MMD_PCS, 0xfe09, 0x1288 },
117 { MDIO_MMD_PCS, 0xfe08, 0x2588 },
118 { MDIO_MMD_PCS, 0xfe11, 0x1105 },
119 { MDIO_MMD_PCS, 0xfe72, 0x042c },
120 { MDIO_MMD_PCS, 0xfbba, 0xcb2 },
121 { MDIO_MMD_PCS, 0xfbbb, 0xc4a },
122 { MDIO_MMD_AN, 0x8032, 0x2020 },
123 { MDIO_MMD_AN, 0x8031, 0xa28 },
124 { MDIO_MMD_AN, 0x8031, 0xc28 },
125 { MDIO_MMD_PCS, 0xffdb, 0xfc10 },
126 { MDIO_MMD_PCS, 0xfe1b, 0x58 },
127 { MDIO_MMD_PCS, 0xfe79, 0x4 },
128 { MDIO_MMD_PCS, 0xfe5f, 0xe8 },
129 { MDIO_MMD_PCS, 0xfe05, 0x755c },
130};
131
132static int mv88q2xxx_soft_reset(struct phy_device *phydev)
133{
134 int ret;
135 int val;
136
137 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
138 MDIO_PCS_1000BT1_CTRL, MDIO_PCS_1000BT1_CTRL_RESET);
139 if (ret < 0)
140 return ret;
141
142 return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
143 MDIO_PCS_1000BT1_CTRL, val,
144 !(val & MDIO_PCS_1000BT1_CTRL_RESET),
145 50000, 600000, true);
146}
147
148static int mv88q2xxx_read_link_gbit(struct phy_device *phydev)
149{
150 int ret;
151 bool link = false;
152
153 /* Read vendor specific Auto-Negotiation status register to get local
154 * and remote receiver status according to software initialization
155 * guide. However, when not in polling mode the local and remote
156 * receiver status are not evaluated due to the Marvell 88Q2xxx APIs.
157 */
158 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
159 if (ret < 0) {
160 return ret;
161 } else if (((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) &&
162 (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) ||
163 !phy_polling_mode(phydev)) {
164 /* The link state is latched low so that momentary link
165 * drops can be detected. Do not double-read the status
166 * in polling mode to detect such short link drops except
167 * the link was already down.
168 */
169 if (!phy_polling_mode(phydev) || !phydev->link) {
170 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
171 MDIO_PCS_1000BT1_STAT);
172 if (ret < 0)
173 return ret;
174 else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
175 link = true;
176 }
177
178 if (!link) {
179 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
180 MDIO_PCS_1000BT1_STAT);
181 if (ret < 0)
182 return ret;
183 else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
184 link = true;
185 }
186 }
187
188 phydev->link = link;
189
190 return 0;
191}
192
193static int mv88q2xxx_read_link_100m(struct phy_device *phydev)
194{
195 int ret;
196
197 /* The link state is latched low so that momentary link
198 * drops can be detected. Do not double-read the status
199 * in polling mode to detect such short link drops except
200 * the link was already down. In case we are not polling,
201 * we always read the realtime status.
202 */
203 if (!phy_polling_mode(phydev)) {
204 phydev->link = false;
205 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
206 MDIO_MMD_PCS_MV_100BT1_STAT2);
207 if (ret < 0)
208 return ret;
209
210 if (ret & MDIO_MMD_PCS_MV_100BT1_STAT2_LINK)
211 phydev->link = true;
212
213 return 0;
214 } else if (!phydev->link) {
215 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
216 MDIO_MMD_PCS_MV_100BT1_STAT1);
217 if (ret < 0)
218 return ret;
219 else if (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK)
220 goto out;
221 }
222
223 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
224 if (ret < 0)
225 return ret;
226
227out:
228 /* Check if we have link and if the remote and local receiver are ok */
229 if ((ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK) &&
230 (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX) &&
231 (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX))
232 phydev->link = true;
233 else
234 phydev->link = false;
235
236 return 0;
237}
238
239static int mv88q2xxx_read_link(struct phy_device *phydev)
240{
241 /* The 88Q2XXX PHYs do not have the PMA/PMD status register available,
242 * therefore we need to read the link status from the vendor specific
243 * registers depending on the speed.
244 */
245
246 if (phydev->speed == SPEED_1000)
247 return mv88q2xxx_read_link_gbit(phydev);
248 else if (phydev->speed == SPEED_100)
249 return mv88q2xxx_read_link_100m(phydev);
250
251 phydev->link = false;
252 return 0;
253}
254
255static int mv88q2xxx_read_master_slave_state(struct phy_device *phydev)
256{
257 int ret;
258
259 phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
260 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
261 if (ret < 0)
262 return ret;
263
264 if (ret & MDIO_MMD_AN_MV_STAT_LOCAL_MASTER)
265 phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
266 else
267 phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
268
269 return 0;
270}
271
272static int mv88q2xxx_read_aneg_speed(struct phy_device *phydev)
273{
274 int ret;
275
276 phydev->speed = SPEED_UNKNOWN;
277 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT2);
278 if (ret < 0)
279 return ret;
280
281 if (!(ret & MDIO_MMD_AN_MV_STAT2_AN_RESOLVED))
282 return 0;
283
284 if (ret & MDIO_MMD_AN_MV_STAT2_100BT1)
285 phydev->speed = SPEED_100;
286 else if (ret & MDIO_MMD_AN_MV_STAT2_1000BT1)
287 phydev->speed = SPEED_1000;
288
289 return 0;
290}
291
292static int mv88q2xxx_read_status(struct phy_device *phydev)
293{
294 int ret;
295
296 if (phydev->autoneg == AUTONEG_ENABLE) {
297 /* We have to get the negotiated speed first, otherwise we are
298 * not able to read the link.
299 */
300 ret = mv88q2xxx_read_aneg_speed(phydev);
301 if (ret < 0)
302 return ret;
303
304 ret = mv88q2xxx_read_link(phydev);
305 if (ret < 0)
306 return ret;
307
308 ret = genphy_c45_read_lpa(phydev);
309 if (ret < 0)
310 return ret;
311
312 ret = genphy_c45_baset1_read_status(phydev);
313 if (ret < 0)
314 return ret;
315
316 ret = mv88q2xxx_read_master_slave_state(phydev);
317 if (ret < 0)
318 return ret;
319
320 phy_resolve_aneg_linkmode(phydev);
321
322 return 0;
323 }
324
325 ret = mv88q2xxx_read_link(phydev);
326 if (ret < 0)
327 return ret;
328
329 return genphy_c45_read_pma(phydev);
330}
331
332static int mv88q2xxx_get_features(struct phy_device *phydev)
333{
334 int ret;
335
336 ret = genphy_c45_pma_read_abilities(phydev);
337 if (ret)
338 return ret;
339
340 /* We need to read the baset1 extended abilities manually because the
341 * PHY does not signalize it has the extended abilities register
342 * available.
343 */
344 ret = genphy_c45_pma_baset1_read_abilities(phydev);
345 if (ret)
346 return ret;
347
348 /* The PHY signalizes it supports autonegotiation. Unfortunately, so
349 * far it was not possible to get a link even when following the init
350 * sequence provided by Marvell. Disable it for now until a proper
351 * workaround is found or a new PHY revision is released.
352 */
353 if (phydev->drv->phy_id == MARVELL_PHY_ID_88Q2110)
354 linkmode_clear_bit(nr: ETHTOOL_LINK_MODE_Autoneg_BIT,
355 addr: phydev->supported);
356
357 return 0;
358}
359
360static int mv88q2xxx_config_aneg(struct phy_device *phydev)
361{
362 int ret;
363
364 ret = genphy_c45_config_aneg(phydev);
365 if (ret)
366 return ret;
367
368 return phydev->drv->soft_reset(phydev);
369}
370
371static int mv88q2xxx_config_init(struct phy_device *phydev)
372{
373 /* The 88Q2XXX PHYs do have the extended ability register available, but
374 * register MDIO_PMA_EXTABLE where they should signalize it does not
375 * work according to specification. Therefore, we force it here.
376 */
377 phydev->pma_extable = MDIO_PMA_EXTABLE_BT1;
378
379 /* Configure interrupt with default settings, output is driven low for
380 * active interrupt and high for inactive.
381 */
382 if (phy_interrupt_is_valid(phydev))
383 return phy_set_bits_mmd(phydev, MDIO_MMD_PCS,
384 MDIO_MMD_PCS_MV_GPIO_INT_CTRL,
385 MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS);
386
387 return 0;
388}
389
390static int mv88q2xxx_get_sqi(struct phy_device *phydev)
391{
392 int ret;
393
394 if (phydev->speed == SPEED_100) {
395 /* Read the SQI from the vendor specific receiver status
396 * register
397 */
398 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
399 MDIO_MMD_PCS_MV_RX_STAT);
400 if (ret < 0)
401 return ret;
402
403 ret = ret >> 12;
404 } else {
405 /* Read from vendor specific registers, they are not documented
406 * but can be found in the Software Initialization Guide. Only
407 * revisions >= A0 are supported.
408 */
409 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, regnum: 0xfc5d, mask: 0xff, set: 0xac);
410 if (ret < 0)
411 return ret;
412
413 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, regnum: 0xfc88);
414 if (ret < 0)
415 return ret;
416 }
417
418 return ret & 0x0f;
419}
420
421static int mv88q2xxx_get_sqi_max(struct phy_device *phydev)
422{
423 return 15;
424}
425
426static int mv88q2xxx_config_intr(struct phy_device *phydev)
427{
428 int ret;
429
430 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
431 /* Enable interrupts for 1000BASE-T1 link up and down events
432 * and enable general interrupts for 100BASE-T1.
433 */
434 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
435 MDIO_MMD_PCS_MV_INT_EN,
436 MDIO_MMD_PCS_MV_INT_EN_LINK_UP |
437 MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN |
438 MDIO_MMD_PCS_MV_INT_EN_100BT1);
439 if (ret < 0)
440 return ret;
441
442 /* Enable interrupts for 100BASE-T1 link events */
443 return phy_write_mmd(phydev, MDIO_MMD_PCS,
444 MDIO_MMD_PCS_MV_100BT1_INT_EN,
445 MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT);
446 } else {
447 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
448 MDIO_MMD_PCS_MV_INT_EN, val: 0);
449 if (ret < 0)
450 return ret;
451
452 return phy_write_mmd(phydev, MDIO_MMD_PCS,
453 MDIO_MMD_PCS_MV_100BT1_INT_EN, val: 0);
454 }
455}
456
457static irqreturn_t mv88q2xxx_handle_interrupt(struct phy_device *phydev)
458{
459 bool trigger_machine = false;
460 int irq;
461
462 /* Before we can acknowledge the 100BT1 general interrupt, that is in
463 * the 1000BT1 interrupt status register, we have to acknowledge any
464 * interrupts that are related to it. Therefore we read first the 100BT1
465 * interrupt status register, followed by reading the 1000BT1 interrupt
466 * status register.
467 */
468
469 irq = phy_read_mmd(phydev, MDIO_MMD_PCS,
470 MDIO_MMD_PCS_MV_COPPER_INT_STAT);
471 if (irq < 0) {
472 phy_error(phydev);
473 return IRQ_NONE;
474 }
475
476 /* Check link status for 100BT1 */
477 if (irq & MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT)
478 trigger_machine = true;
479
480 irq = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_GPIO_INT_STAT);
481 if (irq < 0) {
482 phy_error(phydev);
483 return IRQ_NONE;
484 }
485
486 /* Check link status for 1000BT1 */
487 if ((irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP) ||
488 (irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN))
489 trigger_machine = true;
490
491 if (!trigger_machine)
492 return IRQ_NONE;
493
494 phy_trigger_machine(phydev);
495
496 return IRQ_HANDLED;
497}
498
499static int mv88q2xxx_suspend(struct phy_device *phydev)
500{
501 int ret;
502
503 /* Disable PHY interrupts */
504 if (phy_interrupt_is_valid(phydev)) {
505 phydev->interrupts = PHY_INTERRUPT_DISABLED;
506 ret = mv88q2xxx_config_intr(phydev);
507 if (ret)
508 return ret;
509 }
510
511 return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
512 MDIO_CTRL1_LPOWER);
513}
514
515static int mv88q2xxx_resume(struct phy_device *phydev)
516{
517 int ret;
518
519 /* Enable PHY interrupts */
520 if (phy_interrupt_is_valid(phydev)) {
521 phydev->interrupts = PHY_INTERRUPT_ENABLED;
522 ret = mv88q2xxx_config_intr(phydev);
523 if (ret)
524 return ret;
525 }
526
527 return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
528 MDIO_CTRL1_LPOWER);
529}
530
531#if IS_ENABLED(CONFIG_HWMON)
532static const struct hwmon_channel_info * const mv88q2xxx_hwmon_info[] = {
533 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_ALARM),
534 NULL
535};
536
537static umode_t mv88q2xxx_hwmon_is_visible(const void *data,
538 enum hwmon_sensor_types type,
539 u32 attr, int channel)
540{
541 switch (attr) {
542 case hwmon_temp_input:
543 return 0444;
544 case hwmon_temp_max:
545 return 0644;
546 case hwmon_temp_alarm:
547 return 0444;
548 default:
549 return 0;
550 }
551}
552
553static int mv88q2xxx_hwmon_read(struct device *dev,
554 enum hwmon_sensor_types type,
555 u32 attr, int channel, long *val)
556{
557 struct phy_device *phydev = dev_get_drvdata(dev);
558 int ret;
559
560 switch (attr) {
561 case hwmon_temp_input:
562 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
563 MDIO_MMD_PCS_MV_TEMP_SENSOR3);
564 if (ret < 0)
565 return ret;
566
567 ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK, ret);
568 *val = (ret - 75) * 1000;
569 return 0;
570 case hwmon_temp_max:
571 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
572 MDIO_MMD_PCS_MV_TEMP_SENSOR3);
573 if (ret < 0)
574 return ret;
575
576 ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
577 ret);
578 *val = (ret - 75) * 1000;
579 return 0;
580 case hwmon_temp_alarm:
581 ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
582 MDIO_MMD_PCS_MV_TEMP_SENSOR1);
583 if (ret < 0)
584 return ret;
585
586 *val = !!(ret & MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT);
587 return 0;
588 default:
589 return -EOPNOTSUPP;
590 }
591}
592
593static int mv88q2xxx_hwmon_write(struct device *dev,
594 enum hwmon_sensor_types type, u32 attr,
595 int channel, long val)
596{
597 struct phy_device *phydev = dev_get_drvdata(dev);
598
599 switch (attr) {
600 case hwmon_temp_max:
601 clamp_val(val, -75000, 180000);
602 val = (val / 1000) + 75;
603 val = FIELD_PREP(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
604 val);
605 return phy_modify_mmd(phydev, MDIO_MMD_PCS,
606 MDIO_MMD_PCS_MV_TEMP_SENSOR3,
607 MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
608 set: val);
609 default:
610 return -EOPNOTSUPP;
611 }
612}
613
614static const struct hwmon_ops mv88q2xxx_hwmon_hwmon_ops = {
615 .is_visible = mv88q2xxx_hwmon_is_visible,
616 .read = mv88q2xxx_hwmon_read,
617 .write = mv88q2xxx_hwmon_write,
618};
619
620static const struct hwmon_chip_info mv88q2xxx_hwmon_chip_info = {
621 .ops = &mv88q2xxx_hwmon_hwmon_ops,
622 .info = mv88q2xxx_hwmon_info,
623};
624
625static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
626{
627 struct device *dev = &phydev->mdio.dev;
628 struct device *hwmon;
629 char *hwmon_name;
630 int ret;
631
632 /* Enable temperature sense */
633 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TEMP_SENSOR2,
634 MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK, set: 0);
635 if (ret < 0)
636 return ret;
637
638 hwmon_name = devm_hwmon_sanitize_name(dev, name: dev_name(dev));
639 if (IS_ERR(ptr: hwmon_name))
640 return PTR_ERR(ptr: hwmon_name);
641
642 hwmon = devm_hwmon_device_register_with_info(dev,
643 name: hwmon_name,
644 drvdata: phydev,
645 info: &mv88q2xxx_hwmon_chip_info,
646 NULL);
647
648 return PTR_ERR_OR_ZERO(ptr: hwmon);
649}
650
651#else
652static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
653{
654 return 0;
655}
656#endif
657
658static int mv88q2xxx_probe(struct phy_device *phydev)
659{
660 return mv88q2xxx_hwmon_probe(phydev);
661}
662
663static int mv88q222x_soft_reset(struct phy_device *phydev)
664{
665 int ret;
666
667 /* Enable RESET of DCL */
668 if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) {
669 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, regnum: 0xfe1b, val: 0x48);
670 if (ret < 0)
671 return ret;
672 }
673
674 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL,
675 MDIO_PCS_1000BT1_CTRL_RESET);
676 if (ret < 0)
677 return ret;
678
679 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, regnum: 0xffe4, val: 0xc);
680 if (ret < 0)
681 return ret;
682
683 /* Disable RESET of DCL */
684 if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000)
685 return phy_write_mmd(phydev, MDIO_MMD_PCS, regnum: 0xfe1b, val: 0x58);
686
687 return 0;
688}
689
690static int mv88q222x_revb0_config_init(struct phy_device *phydev)
691{
692 int ret, i;
693
694 for (i = 0; i < ARRAY_SIZE(mv88q222x_revb0_init_seq0); i++) {
695 ret = phy_write_mmd(phydev, devad: mv88q222x_revb0_init_seq0[i].devad,
696 regnum: mv88q222x_revb0_init_seq0[i].regnum,
697 val: mv88q222x_revb0_init_seq0[i].val);
698 if (ret < 0)
699 return ret;
700 }
701
702 usleep_range(min: 5000, max: 10000);
703
704 for (i = 0; i < ARRAY_SIZE(mv88q222x_revb0_init_seq1); i++) {
705 ret = phy_write_mmd(phydev, devad: mv88q222x_revb0_init_seq1[i].devad,
706 regnum: mv88q222x_revb0_init_seq1[i].regnum,
707 val: mv88q222x_revb0_init_seq1[i].val);
708 if (ret < 0)
709 return ret;
710 }
711
712 return mv88q2xxx_config_init(phydev);
713}
714
715static int mv88q222x_cable_test_start(struct phy_device *phydev)
716{
717 int ret;
718
719 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
720 MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF, val: 0x0058);
721 if (ret < 0)
722 return ret;
723
724 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
725 MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE, val: 0x00eb);
726 if (ret < 0)
727 return ret;
728
729 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
730 MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE, val: 0x010e);
731 if (ret < 0)
732 return ret;
733
734 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET,
735 val: 0x0d90);
736 if (ret < 0)
737 return ret;
738
739 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS,
740 MDIO_MMD_PCS_MV_TDR_STATUS_ON);
741 if (ret < 0)
742 return ret;
743
744 /* According to the Marvell API the test is finished within 500 ms */
745 msleep(msecs: 500);
746
747 return 0;
748}
749
750static int mv88q222x_cable_test_get_status(struct phy_device *phydev,
751 bool *finished)
752{
753 int ret, status;
754 u32 dist;
755
756 status = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS);
757 if (status < 0)
758 return status;
759
760 ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET,
761 MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST | 0xd90);
762 if (ret < 0)
763 return ret;
764
765 /* Test could not be finished */
766 if (FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_MASK, status) !=
767 MDIO_MMD_PCS_MV_TDR_STATUS_OFF)
768 return -ETIMEDOUT;
769
770 *finished = true;
771 /* Fault length reported in meters, convert to centimeters */
772 dist = FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK, status) * 100;
773 switch (status & MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK) {
774 case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN:
775 ethnl_cable_test_result(phydev, pair: ETHTOOL_A_CABLE_PAIR_A,
776 result: ETHTOOL_A_CABLE_RESULT_CODE_OPEN);
777 ethnl_cable_test_fault_length(phydev, pair: ETHTOOL_A_CABLE_PAIR_A,
778 cm: dist);
779 break;
780 case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT:
781 ethnl_cable_test_result(phydev, pair: ETHTOOL_A_CABLE_PAIR_A,
782 result: ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT);
783 ethnl_cable_test_fault_length(phydev, pair: ETHTOOL_A_CABLE_PAIR_A,
784 cm: dist);
785 break;
786 case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK:
787 ethnl_cable_test_result(phydev, pair: ETHTOOL_A_CABLE_PAIR_A,
788 result: ETHTOOL_A_CABLE_RESULT_CODE_OK);
789 break;
790 default:
791 ethnl_cable_test_result(phydev, pair: ETHTOOL_A_CABLE_PAIR_A,
792 result: ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC);
793 }
794
795 return 0;
796}
797
798static struct phy_driver mv88q2xxx_driver[] = {
799 {
800 .phy_id = MARVELL_PHY_ID_88Q2110,
801 .phy_id_mask = MARVELL_PHY_ID_MASK,
802 .name = "mv88q2110",
803 .get_features = mv88q2xxx_get_features,
804 .config_aneg = mv88q2xxx_config_aneg,
805 .config_init = mv88q2xxx_config_init,
806 .read_status = mv88q2xxx_read_status,
807 .soft_reset = mv88q2xxx_soft_reset,
808 .set_loopback = genphy_c45_loopback,
809 .get_sqi = mv88q2xxx_get_sqi,
810 .get_sqi_max = mv88q2xxx_get_sqi_max,
811 },
812 {
813 PHY_ID_MATCH_EXACT(PHY_ID_88Q2220_REVB0),
814 .name = "mv88q2220",
815 .flags = PHY_POLL_CABLE_TEST,
816 .probe = mv88q2xxx_probe,
817 .get_features = mv88q2xxx_get_features,
818 .config_aneg = mv88q2xxx_config_aneg,
819 .aneg_done = genphy_c45_aneg_done,
820 .config_init = mv88q222x_revb0_config_init,
821 .read_status = mv88q2xxx_read_status,
822 .soft_reset = mv88q222x_soft_reset,
823 .config_intr = mv88q2xxx_config_intr,
824 .handle_interrupt = mv88q2xxx_handle_interrupt,
825 .set_loopback = genphy_c45_loopback,
826 .cable_test_start = mv88q222x_cable_test_start,
827 .cable_test_get_status = mv88q222x_cable_test_get_status,
828 .get_sqi = mv88q2xxx_get_sqi,
829 .get_sqi_max = mv88q2xxx_get_sqi_max,
830 .suspend = mv88q2xxx_suspend,
831 .resume = mv88q2xxx_resume,
832 },
833};
834
835module_phy_driver(mv88q2xxx_driver);
836
837static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
838 { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
839 { PHY_ID_MATCH_EXACT(PHY_ID_88Q2220_REVB0), },
840 { /*sentinel*/ }
841};
842MODULE_DEVICE_TABLE(mdio, mv88q2xxx_tbl);
843
844MODULE_DESCRIPTION("Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet PHY driver");
845MODULE_LICENSE("GPL");
846

source code of linux/drivers/net/phy/marvell-88q2xxx.c