]> git.ipfire.org Git - people/ms/linux.git/blame - drivers/net/phy/marvell.c
net: geneve: check skb is large enough for IPv4/IPv6 header
[people/ms/linux.git] / drivers / net / phy / marvell.c
CommitLineData
a2443fd1 1// SPDX-License-Identifier: GPL-2.0+
00db8189
AF
2/*
3 * drivers/net/phy/marvell.c
4 *
5 * Driver for Marvell PHYs
6 *
7 * Author: Andy Fleming
8 *
9 * Copyright (c) 2004 Freescale Semiconductor, Inc.
10 *
3871c387 11 * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>
00db8189 12 */
00db8189 13#include <linux/kernel.h>
00db8189 14#include <linux/string.h>
0b04680f 15#include <linux/ctype.h>
00db8189
AF
16#include <linux/errno.h>
17#include <linux/unistd.h>
0b04680f 18#include <linux/hwmon.h>
00db8189
AF
19#include <linux/interrupt.h>
20#include <linux/init.h>
21#include <linux/delay.h>
22#include <linux/netdevice.h>
23#include <linux/etherdevice.h>
24#include <linux/skbuff.h>
25#include <linux/spinlock.h>
26#include <linux/mm.h>
27#include <linux/module.h>
00db8189
AF
28#include <linux/mii.h>
29#include <linux/ethtool.h>
fc879f72 30#include <linux/ethtool_netlink.h>
00db8189 31#include <linux/phy.h>
2f495c39 32#include <linux/marvell_phy.h>
69f42be8 33#include <linux/bitfield.h>
cf41a51d 34#include <linux/of.h>
00db8189 35
eea3b201 36#include <linux/io.h>
00db8189 37#include <asm/irq.h>
eea3b201 38#include <linux/uaccess.h>
00db8189 39
27d916d6 40#define MII_MARVELL_PHY_PAGE 22
52295666
AL
41#define MII_MARVELL_COPPER_PAGE 0x00
42#define MII_MARVELL_FIBER_PAGE 0x01
43#define MII_MARVELL_MSCR_PAGE 0x02
44#define MII_MARVELL_LED_PAGE 0x03
0c9bcc1d 45#define MII_MARVELL_VCT5_PAGE 0x05
52295666 46#define MII_MARVELL_MISC_TEST_PAGE 0x06
fc879f72 47#define MII_MARVELL_VCT7_PAGE 0x07
52295666 48#define MII_MARVELL_WOL_PAGE 0x11
27d916d6 49
00db8189
AF
50#define MII_M1011_IEVENT 0x13
51#define MII_M1011_IEVENT_CLEAR 0x0000
52
53#define MII_M1011_IMASK 0x12
54#define MII_M1011_IMASK_INIT 0x6400
55#define MII_M1011_IMASK_CLEAR 0x0000
56
fecd5e91
AL
57#define MII_M1011_PHY_SCR 0x10
58#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)
f8d975be 59#define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12)
a3bdfce7 60#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8
fecd5e91
AL
61#define MII_M1011_PHY_SCR_MDI (0x0 << 5)
62#define MII_M1011_PHY_SCR_MDI_X (0x1 << 5)
63#define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5)
76884679 64
a3bdfce7
HK
65#define MII_M1011_PHY_SSR 0x11
66#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5)
67
76884679
AF
68#define MII_M1111_PHY_LED_CONTROL 0x18
69#define MII_M1111_PHY_LED_DIRECT 0x4100
70#define MII_M1111_PHY_LED_COMBINE 0x411c
895ee682 71#define MII_M1111_PHY_EXT_CR 0x14
5c6bc519
HK
72#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9)
73#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 8
74#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8)
61111598
AL
75#define MII_M1111_RGMII_RX_DELAY BIT(7)
76#define MII_M1111_RGMII_TX_DELAY BIT(1)
895ee682 77#define MII_M1111_PHY_EXT_SR 0x1b
be937f1f
AS
78
79#define MII_M1111_HWCFG_MODE_MASK 0xf
be937f1f 80#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3
4117b5be 81#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4
865b813a 82#define MII_M1111_HWCFG_MODE_RTBI 0x7
1887023a 83#define MII_M1111_HWCFG_MODE_COPPER_1000X_AN 0x8
5f8cbc13 84#define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9
865b813a 85#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb
1887023a
RH
86#define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN 0xc
87#define MII_M1111_HWCFG_SERIAL_AN_BYPASS BIT(12)
865b813a
AL
88#define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13)
89#define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15)
be937f1f 90
c477d044
CC
91#define MII_88E1121_PHY_MSCR_REG 21
92#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5)
93#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
424ca4c5 94#define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4))
c477d044 95
0b04680f
AL
96#define MII_88E1121_MISC_TEST 0x1a
97#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00
98#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8
99#define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7)
100#define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6)
101#define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5)
102#define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f
103
104#define MII_88E1510_TEMP_SENSOR 0x1b
105#define MII_88E1510_TEMP_SENSOR_MASK 0xff
106
69f42be8
HK
107#define MII_88E1540_COPPER_CTRL3 0x1a
108#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10)
109#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0
110#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1
111#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2
112#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3
113#define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9)
114
fee2d546
AL
115#define MII_88E6390_MISC_TEST 0x1b
116#define MII_88E6390_MISC_TEST_SAMPLE_1S 0
117#define MII_88E6390_MISC_TEST_SAMPLE_10MS BIT(14)
118#define MII_88E6390_MISC_TEST_SAMPLE_DISABLE BIT(15)
119#define MII_88E6390_MISC_TEST_SAMPLE_ENABLE 0
120#define MII_88E6390_MISC_TEST_SAMPLE_MASK (0x3 << 14)
121
122#define MII_88E6390_TEMP_SENSOR 0x1c
123#define MII_88E6390_TEMP_SENSOR_MASK 0xff
124#define MII_88E6390_TEMP_SENSOR_SAMPLES 10
125
337ac9d5
CC
126#define MII_88E1318S_PHY_MSCR1_REG 16
127#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
3ff1c259 128
3871c387 129/* Copper Specific Interrupt Enable Register */
8cf8b87b 130#define MII_88E1318S_PHY_CSIER 0x12
3871c387 131/* WOL Event Interrupt Enable */
8cf8b87b 132#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
3871c387
MS
133
134/* LED Timer Control Register */
8cf8b87b
AL
135#define MII_88E1318S_PHY_LED_TCR 0x12
136#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
137#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
138#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)
3871c387
MS
139
140/* Magic Packet MAC address registers */
8cf8b87b
AL
141#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17
142#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18
143#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19
3871c387 144
8cf8b87b
AL
145#define MII_88E1318S_PHY_WOL_CTRL 0x10
146#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12)
147#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
3871c387 148
07777246 149#define MII_PHY_LED_CTRL 16
140bc929 150#define MII_88E1121_PHY_LED_DEF 0x0030
07777246 151#define MII_88E1510_PHY_LED_DEF 0x1177
a93f7fe1 152#define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040
140bc929 153
be937f1f
AS
154#define MII_M1011_PHY_STATUS 0x11
155#define MII_M1011_PHY_STATUS_1000 0x8000
156#define MII_M1011_PHY_STATUS_100 0x4000
157#define MII_M1011_PHY_STATUS_SPD_MASK 0xc000
158#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000
159#define MII_M1011_PHY_STATUS_RESOLVED 0x0800
160#define MII_M1011_PHY_STATUS_LINK 0x0400
161
6b358aed
SH
162#define MII_88E3016_PHY_SPEC_CTRL 0x10
163#define MII_88E3016_DISABLE_SCRAMBLER 0x0200
164#define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030
76884679 165
930b37ee
SR
166#define MII_88E1510_GEN_CTRL_REG_1 0x14
167#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7
168#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */
169#define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */
170
0c9bcc1d
AL
171#define MII_VCT5_TX_RX_MDI0_COUPLING 0x10
172#define MII_VCT5_TX_RX_MDI1_COUPLING 0x11
173#define MII_VCT5_TX_RX_MDI2_COUPLING 0x12
174#define MII_VCT5_TX_RX_MDI3_COUPLING 0x13
175#define MII_VCT5_TX_RX_AMPLITUDE_MASK 0x7f00
176#define MII_VCT5_TX_RX_AMPLITUDE_SHIFT 8
177#define MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION BIT(15)
178
179#define MII_VCT5_CTRL 0x17
180#define MII_VCT5_CTRL_ENABLE BIT(15)
181#define MII_VCT5_CTRL_COMPLETE BIT(14)
182#define MII_VCT5_CTRL_TX_SAME_CHANNEL (0x0 << 11)
183#define MII_VCT5_CTRL_TX0_CHANNEL (0x4 << 11)
184#define MII_VCT5_CTRL_TX1_CHANNEL (0x5 << 11)
185#define MII_VCT5_CTRL_TX2_CHANNEL (0x6 << 11)
186#define MII_VCT5_CTRL_TX3_CHANNEL (0x7 << 11)
187#define MII_VCT5_CTRL_SAMPLES_2 (0x0 << 8)
188#define MII_VCT5_CTRL_SAMPLES_4 (0x1 << 8)
189#define MII_VCT5_CTRL_SAMPLES_8 (0x2 << 8)
190#define MII_VCT5_CTRL_SAMPLES_16 (0x3 << 8)
191#define MII_VCT5_CTRL_SAMPLES_32 (0x4 << 8)
192#define MII_VCT5_CTRL_SAMPLES_64 (0x5 << 8)
193#define MII_VCT5_CTRL_SAMPLES_128 (0x6 << 8)
194#define MII_VCT5_CTRL_SAMPLES_DEFAULT (0x6 << 8)
195#define MII_VCT5_CTRL_SAMPLES_256 (0x7 << 8)
196#define MII_VCT5_CTRL_SAMPLES_SHIFT 8
197#define MII_VCT5_CTRL_MODE_MAXIMUM_PEEK (0x0 << 6)
198#define MII_VCT5_CTRL_MODE_FIRST_LAST_PEEK (0x1 << 6)
199#define MII_VCT5_CTRL_MODE_OFFSET (0x2 << 6)
200#define MII_VCT5_CTRL_SAMPLE_POINT (0x3 << 6)
201#define MII_VCT5_CTRL_PEEK_HYST_DEFAULT 3
202
203#define MII_VCT5_SAMPLE_POINT_DISTANCE 0x18
f2bc8ad3 204#define MII_VCT5_SAMPLE_POINT_DISTANCE_MAX 511
0c9bcc1d
AL
205#define MII_VCT5_TX_PULSE_CTRL 0x1c
206#define MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN BIT(12)
207#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS (0x0 << 10)
208#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_96nS (0x1 << 10)
209#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_64nS (0x2 << 10)
210#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS (0x3 << 10)
211#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_SHIFT 10
212#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_1000mV (0x0 << 8)
213#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_750mV (0x1 << 8)
214#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_500mV (0x2 << 8)
215#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_250mV (0x3 << 8)
216#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_SHIFT 8
217#define MII_VCT5_TX_PULSE_CTRL_MAX_AMP BIT(7)
218#define MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV (0x6 << 0)
219
db8668a1
AL
220/* For TDR measurements less than 11 meters, a short pulse should be
221 * used.
222 */
223#define TDR_SHORT_CABLE_LENGTH 11
224
fc879f72
AL
225#define MII_VCT7_PAIR_0_DISTANCE 0x10
226#define MII_VCT7_PAIR_1_DISTANCE 0x11
227#define MII_VCT7_PAIR_2_DISTANCE 0x12
228#define MII_VCT7_PAIR_3_DISTANCE 0x13
229
230#define MII_VCT7_RESULTS 0x14
231#define MII_VCT7_RESULTS_PAIR3_MASK 0xf000
232#define MII_VCT7_RESULTS_PAIR2_MASK 0x0f00
233#define MII_VCT7_RESULTS_PAIR1_MASK 0x00f0
234#define MII_VCT7_RESULTS_PAIR0_MASK 0x000f
235#define MII_VCT7_RESULTS_PAIR3_SHIFT 12
236#define MII_VCT7_RESULTS_PAIR2_SHIFT 8
237#define MII_VCT7_RESULTS_PAIR1_SHIFT 4
238#define MII_VCT7_RESULTS_PAIR0_SHIFT 0
239#define MII_VCT7_RESULTS_INVALID 0
240#define MII_VCT7_RESULTS_OK 1
241#define MII_VCT7_RESULTS_OPEN 2
242#define MII_VCT7_RESULTS_SAME_SHORT 3
243#define MII_VCT7_RESULTS_CROSS_SHORT 4
244#define MII_VCT7_RESULTS_BUSY 9
245
246#define MII_VCT7_CTRL 0x15
247#define MII_VCT7_CTRL_RUN_NOW BIT(15)
248#define MII_VCT7_CTRL_RUN_ANEG BIT(14)
249#define MII_VCT7_CTRL_DISABLE_CROSS BIT(13)
250#define MII_VCT7_CTRL_RUN_AFTER_BREAK_LINK BIT(12)
251#define MII_VCT7_CTRL_IN_PROGRESS BIT(11)
252#define MII_VCT7_CTRL_METERS BIT(10)
253#define MII_VCT7_CTRL_CENTIMETERS 0
254
8cf8b87b 255#define LPA_PAUSE_FIBER 0x180
6cfb3bcc
CAC
256#define LPA_PAUSE_ASYM_FIBER 0x100
257
2170fef7 258#define NB_FIBER_STATS 1
6cfb3bcc 259
00db8189
AF
260MODULE_DESCRIPTION("Marvell PHY driver");
261MODULE_AUTHOR("Andy Fleming");
262MODULE_LICENSE("GPL");
263
d2fa47d9
AL
264struct marvell_hw_stat {
265 const char *string;
266 u8 page;
267 u8 reg;
268 u8 bits;
269};
270
271static struct marvell_hw_stat marvell_hw_stats[] = {
2170fef7 272 { "phy_receive_errors_copper", 0, 21, 16},
d2fa47d9 273 { "phy_idle_errors", 0, 10, 8 },
2170fef7 274 { "phy_receive_errors_fiber", 1, 21, 16},
d2fa47d9
AL
275};
276
277struct marvell_priv {
278 u64 stats[ARRAY_SIZE(marvell_hw_stats)];
0b04680f
AL
279 char *hwmon_name;
280 struct device *hwmon_dev;
0c9bcc1d 281 bool cable_test_tdr;
f2bc8ad3
AL
282 u32 first;
283 u32 last;
284 u32 step;
285 s8 pair;
d2fa47d9
AL
286};
287
424ca4c5 288static int marvell_read_page(struct phy_device *phydev)
6427bb2d 289{
424ca4c5 290 return __phy_read(phydev, MII_MARVELL_PHY_PAGE);
6427bb2d
AL
291}
292
424ca4c5 293static int marvell_write_page(struct phy_device *phydev, int page)
6427bb2d 294{
424ca4c5 295 return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
6427bb2d
AL
296}
297
424ca4c5 298static int marvell_set_page(struct phy_device *phydev, int page)
53798328 299{
424ca4c5 300 return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
53798328
AL
301}
302
00db8189
AF
303static int marvell_ack_interrupt(struct phy_device *phydev)
304{
305 int err;
306
307 /* Clear the interrupts by reading the reg */
308 err = phy_read(phydev, MII_M1011_IEVENT);
309
310 if (err < 0)
311 return err;
312
313 return 0;
314}
315
316static int marvell_config_intr(struct phy_device *phydev)
317{
318 int err;
319
1f6d0f26
IC
320 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
321 err = marvell_ack_interrupt(phydev);
322 if (err)
323 return err;
324
23beb38f
AL
325 err = phy_write(phydev, MII_M1011_IMASK,
326 MII_M1011_IMASK_INIT);
1f6d0f26 327 } else {
23beb38f
AL
328 err = phy_write(phydev, MII_M1011_IMASK,
329 MII_M1011_IMASK_CLEAR);
1f6d0f26
IC
330 if (err)
331 return err;
332
333 err = marvell_ack_interrupt(phydev);
334 }
00db8189
AF
335
336 return err;
337}
338
a0723b37
IC
339static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
340{
341 int irq_status;
342
343 irq_status = phy_read(phydev, MII_M1011_IEVENT);
344 if (irq_status < 0) {
345 phy_error(phydev);
346 return IRQ_NONE;
347 }
348
349 if (!(irq_status & MII_M1011_IMASK_INIT))
350 return IRQ_NONE;
351
352 phy_trigger_machine(phydev);
353
354 return IRQ_HANDLED;
355}
356
239aa55b
DT
357static int marvell_set_polarity(struct phy_device *phydev, int polarity)
358{
359 int reg;
360 int err;
361 int val;
362
363 /* get the current settings */
364 reg = phy_read(phydev, MII_M1011_PHY_SCR);
365 if (reg < 0)
366 return reg;
367
368 val = reg;
369 val &= ~MII_M1011_PHY_SCR_AUTO_CROSS;
370 switch (polarity) {
371 case ETH_TP_MDI:
372 val |= MII_M1011_PHY_SCR_MDI;
373 break;
374 case ETH_TP_MDI_X:
375 val |= MII_M1011_PHY_SCR_MDI_X;
376 break;
377 case ETH_TP_MDI_AUTO:
378 case ETH_TP_MDI_INVALID:
379 default:
380 val |= MII_M1011_PHY_SCR_AUTO_CROSS;
381 break;
382 }
383
384 if (val != reg) {
385 /* Set the new polarity value in the register */
386 err = phy_write(phydev, MII_M1011_PHY_SCR, val);
387 if (err)
388 return err;
389 }
390
d6ab9336 391 return val != reg;
239aa55b
DT
392}
393
00db8189
AF
394static int marvell_config_aneg(struct phy_device *phydev)
395{
d6ab9336 396 int changed = 0;
00db8189
AF
397 int err;
398
4e26c5c3 399 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
76884679
AF
400 if (err < 0)
401 return err;
402
d6ab9336
FF
403 changed = err;
404
76884679
AF
405 err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
406 MII_M1111_PHY_LED_DIRECT);
407 if (err < 0)
408 return err;
00db8189
AF
409
410 err = genphy_config_aneg(phydev);
8ff44985
AV
411 if (err < 0)
412 return err;
00db8189 413
d6ab9336 414 if (phydev->autoneg != AUTONEG_ENABLE || changed) {
0c3439bc 415 /* A write to speed/duplex bits (that is performed by
8ff44985
AV
416 * genphy_config_aneg() call above) must be followed by
417 * a software reset. Otherwise, the write has no effect.
418 */
34386344 419 err = genphy_soft_reset(phydev);
8ff44985
AV
420 if (err < 0)
421 return err;
422 }
423
424 return 0;
00db8189
AF
425}
426
f2899788
AL
427static int m88e1101_config_aneg(struct phy_device *phydev)
428{
429 int err;
430
431 /* This Marvell PHY has an errata which requires
432 * that certain registers get written in order
433 * to restart autonegotiation
434 */
34386344 435 err = genphy_soft_reset(phydev);
f2899788
AL
436 if (err < 0)
437 return err;
438
439 err = phy_write(phydev, 0x1d, 0x1f);
440 if (err < 0)
441 return err;
442
443 err = phy_write(phydev, 0x1e, 0x200c);
444 if (err < 0)
445 return err;
446
447 err = phy_write(phydev, 0x1d, 0x5);
448 if (err < 0)
449 return err;
450
451 err = phy_write(phydev, 0x1e, 0);
452 if (err < 0)
453 return err;
454
455 err = phy_write(phydev, 0x1e, 0x100);
456 if (err < 0)
457 return err;
458
459 return marvell_config_aneg(phydev);
460}
461
5cd119d9 462#if IS_ENABLED(CONFIG_OF_MDIO)
0c3439bc 463/* Set and/or override some configuration registers based on the
cf41a51d
DD
464 * marvell,reg-init property stored in the of_node for the phydev.
465 *
466 * marvell,reg-init = <reg-page reg mask value>,...;
467 *
468 * There may be one or more sets of <reg-page reg mask value>:
469 *
470 * reg-page: which register bank to use.
471 * reg: the register.
472 * mask: if non-zero, ANDed with existing register value.
473 * value: ORed with the masked value and written to the regiser.
474 *
475 */
476static int marvell_of_reg_init(struct phy_device *phydev)
477{
478 const __be32 *paddr;
424ca4c5 479 int len, i, saved_page, current_page, ret = 0;
cf41a51d 480
e5a03bfd 481 if (!phydev->mdio.dev.of_node)
cf41a51d
DD
482 return 0;
483
e5a03bfd
AL
484 paddr = of_get_property(phydev->mdio.dev.of_node,
485 "marvell,reg-init", &len);
cf41a51d
DD
486 if (!paddr || len < (4 * sizeof(*paddr)))
487 return 0;
488
424ca4c5 489 saved_page = phy_save_page(phydev);
cf41a51d 490 if (saved_page < 0)
424ca4c5 491 goto err;
cf41a51d
DD
492 current_page = saved_page;
493
cf41a51d
DD
494 len /= sizeof(*paddr);
495 for (i = 0; i < len - 3; i += 4) {
6427bb2d 496 u16 page = be32_to_cpup(paddr + i);
cf41a51d
DD
497 u16 reg = be32_to_cpup(paddr + i + 1);
498 u16 mask = be32_to_cpup(paddr + i + 2);
499 u16 val_bits = be32_to_cpup(paddr + i + 3);
500 int val;
501
6427bb2d
AL
502 if (page != current_page) {
503 current_page = page;
424ca4c5 504 ret = marvell_write_page(phydev, page);
cf41a51d
DD
505 if (ret < 0)
506 goto err;
507 }
508
509 val = 0;
510 if (mask) {
424ca4c5 511 val = __phy_read(phydev, reg);
cf41a51d
DD
512 if (val < 0) {
513 ret = val;
514 goto err;
515 }
516 val &= mask;
517 }
518 val |= val_bits;
519
424ca4c5 520 ret = __phy_write(phydev, reg, val);
cf41a51d
DD
521 if (ret < 0)
522 goto err;
cf41a51d
DD
523 }
524err:
424ca4c5 525 return phy_restore_page(phydev, saved_page, ret);
cf41a51d
DD
526}
527#else
528static int marvell_of_reg_init(struct phy_device *phydev)
529{
530 return 0;
531}
532#endif /* CONFIG_OF_MDIO */
533
864dc729 534static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
140bc929 535{
424ca4c5 536 int mscr;
864dc729
AL
537
538 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
424ca4c5
RK
539 mscr = MII_88E1121_PHY_MSCR_RX_DELAY |
540 MII_88E1121_PHY_MSCR_TX_DELAY;
864dc729 541 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
424ca4c5 542 mscr = MII_88E1121_PHY_MSCR_RX_DELAY;
864dc729 543 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
424ca4c5
RK
544 mscr = MII_88E1121_PHY_MSCR_TX_DELAY;
545 else
546 mscr = 0;
140bc929 547
424ca4c5
RK
548 return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
549 MII_88E1121_PHY_MSCR_REG,
550 MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
864dc729
AL
551}
552
553static int m88e1121_config_aneg(struct phy_device *phydev)
554{
d6ab9336 555 int changed = 0;
864dc729
AL
556 int err = 0;
557
558 if (phy_interface_is_rgmii(phydev)) {
559 err = m88e1121_config_aneg_rgmii_delays(phydev);
fea23fb5 560 if (err < 0)
864dc729
AL
561 return err;
562 }
563
d6ab9336 564 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
140bc929
SP
565 if (err < 0)
566 return err;
567
d6ab9336
FF
568 changed = err;
569
570 err = genphy_config_aneg(phydev);
140bc929
SP
571 if (err < 0)
572 return err;
573
4b1bd697 574 if (phydev->autoneg != AUTONEG_ENABLE || changed) {
d6ab9336
FF
575 /* A software reset is used to ensure a "commit" of the
576 * changes is done.
577 */
578 err = genphy_soft_reset(phydev);
579 if (err < 0)
580 return err;
581 }
582
583 return 0;
140bc929
SP
584}
585
337ac9d5 586static int m88e1318_config_aneg(struct phy_device *phydev)
3ff1c259 587{
424ca4c5 588 int err;
3ff1c259 589
424ca4c5
RK
590 err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
591 MII_88E1318S_PHY_MSCR1_REG,
592 0, MII_88E1318S_PHY_MSCR1_PAD_ODD);
3ff1c259
CC
593 if (err < 0)
594 return err;
595
596 return m88e1121_config_aneg(phydev);
597}
598
78301ebe 599/**
3c1bcc86
AL
600 * linkmode_adv_to_fiber_adv_t
601 * @advertise: the linkmode advertisement settings
78301ebe 602 *
3c1bcc86
AL
603 * A small helper function that translates linkmode advertisement
604 * settings to phy autonegotiation advertisements for the MII_ADV
605 * register for fiber link.
78301ebe 606 */
3c1bcc86 607static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise)
78301ebe
CAC
608{
609 u32 result = 0;
610
3c1bcc86 611 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise))
20ecf424 612 result |= ADVERTISE_1000XHALF;
3c1bcc86 613 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise))
20ecf424 614 result |= ADVERTISE_1000XFULL;
78301ebe 615
3c1bcc86
AL
616 if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) &&
617 linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
20ecf424 618 result |= ADVERTISE_1000XPSE_ASYM;
3c1bcc86 619 else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
20ecf424 620 result |= ADVERTISE_1000XPAUSE;
78301ebe
CAC
621
622 return result;
623}
624
625/**
626 * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR
627 * @phydev: target phy_device struct
628 *
629 * Description: If auto-negotiation is enabled, we configure the
630 * advertising, and then restart auto-negotiation. If it is not
631 * enabled, then we write the BMCR. Adapted for fiber link in
632 * some Marvell's devices.
633 */
634static int marvell_config_aneg_fiber(struct phy_device *phydev)
635{
636 int changed = 0;
637 int err;
9f4bae70 638 u16 adv;
78301ebe
CAC
639
640 if (phydev->autoneg != AUTONEG_ENABLE)
641 return genphy_setup_forced(phydev);
642
643 /* Only allow advertising what this PHY supports */
3c1bcc86
AL
644 linkmode_and(phydev->advertising, phydev->advertising,
645 phydev->supported);
78301ebe 646
9f4bae70 647 adv = linkmode_adv_to_fiber_adv_t(phydev->advertising);
78301ebe 648
9f4bae70
RK
649 /* Setup fiber advertisement */
650 err = phy_modify_changed(phydev, MII_ADVERTISE,
651 ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |
652 ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,
653 adv);
654 if (err < 0)
655 return err;
656 if (err > 0)
78301ebe 657 changed = 1;
78301ebe 658
b5abac2d 659 return genphy_check_and_restart_aneg(phydev, changed);
78301ebe
CAC
660}
661
1887023a
RH
662static int m88e1111_config_aneg(struct phy_device *phydev)
663{
664 int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
665 int err;
666
667 if (extsr < 0)
668 return extsr;
669
670 /* If not using SGMII or copper 1000BaseX modes, use normal process.
671 * Steps below are only required for these modes.
672 */
673 if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
674 (extsr & MII_M1111_HWCFG_MODE_MASK) !=
675 MII_M1111_HWCFG_MODE_COPPER_1000X_AN)
676 return marvell_config_aneg(phydev);
677
678 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
679 if (err < 0)
680 goto error;
681
682 /* Configure the copper link first */
683 err = marvell_config_aneg(phydev);
684 if (err < 0)
685 goto error;
686
1887023a
RH
687 /* Then the fiber link */
688 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
689 if (err < 0)
690 goto error;
691
06b334f0
RH
692 if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
693 /* Do not touch the fiber advertisement if we're in copper->sgmii mode.
694 * Just ensure that SGMII-side autonegotiation is enabled.
695 * If we switched from some other mode to SGMII it may not be.
696 */
697 err = genphy_check_and_restart_aneg(phydev, false);
698 else
699 err = marvell_config_aneg_fiber(phydev);
1887023a
RH
700 if (err < 0)
701 goto error;
702
703 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
704
705error:
706 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
707 return err;
708}
709
10e24caa
MS
710static int m88e1510_config_aneg(struct phy_device *phydev)
711{
712 int err;
713
52295666 714 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
78301ebe
CAC
715 if (err < 0)
716 goto error;
717
718 /* Configure the copper link first */
10e24caa
MS
719 err = m88e1318_config_aneg(phydev);
720 if (err < 0)
78301ebe 721 goto error;
10e24caa 722
de9c4e06
RK
723 /* Do not touch the fiber page if we're in copper->sgmii mode */
724 if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
725 return 0;
726
78301ebe 727 /* Then the fiber link */
52295666 728 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
78301ebe
CAC
729 if (err < 0)
730 goto error;
731
732 err = marvell_config_aneg_fiber(phydev);
733 if (err < 0)
734 goto error;
735
52295666 736 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
78301ebe
CAC
737
738error:
52295666 739 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
78301ebe 740 return err;
79be1a1c
CG
741}
742
07777246
WD
743static void marvell_config_led(struct phy_device *phydev)
744{
745 u16 def_config;
746 int err;
747
748 switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) {
749 /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
750 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R):
751 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S):
752 def_config = MII_88E1121_PHY_LED_DEF;
753 break;
754 /* Default PHY LED config:
755 * LED[0] .. 1000Mbps Link
756 * LED[1] .. 100Mbps Link
757 * LED[2] .. Blink, Activity
758 */
759 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510):
a93f7fe1
JS
760 if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE)
761 def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE;
762 else
763 def_config = MII_88E1510_PHY_LED_DEF;
07777246
WD
764 break;
765 default:
766 return;
767 }
768
769 err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,
770 def_config);
771 if (err < 0)
ab2a605f 772 phydev_warn(phydev, "Fail to config marvell phy LED.\n");
07777246
WD
773}
774
79be1a1c
CG
775static int marvell_config_init(struct phy_device *phydev)
776{
85bec4bc 777 /* Set default LED */
07777246
WD
778 marvell_config_led(phydev);
779
79be1a1c 780 /* Set registers from marvell,reg-init DT property */
10e24caa
MS
781 return marvell_of_reg_init(phydev);
782}
783
6b358aed
SH
784static int m88e3016_config_init(struct phy_device *phydev)
785{
fea23fb5 786 int ret;
6b358aed
SH
787
788 /* Enable Scrambler and Auto-Crossover */
fea23fb5 789 ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL,
f102852f 790 MII_88E3016_DISABLE_SCRAMBLER,
fea23fb5
RK
791 MII_88E3016_AUTO_MDIX_CROSSOVER);
792 if (ret < 0)
793 return ret;
6b358aed 794
79be1a1c 795 return marvell_config_init(phydev);
6b358aed
SH
796}
797
865b813a
AL
798static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,
799 u16 mode,
800 int fibre_copper_auto)
801{
865b813a 802 if (fibre_copper_auto)
fea23fb5 803 mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
865b813a 804
fea23fb5 805 return phy_modify(phydev, MII_M1111_PHY_EXT_SR,
f102852f
RK
806 MII_M1111_HWCFG_MODE_MASK |
807 MII_M1111_HWCFG_FIBER_COPPER_AUTO |
808 MII_M1111_HWCFG_FIBER_COPPER_RES,
fea23fb5 809 mode);
865b813a
AL
810}
811
61111598 812static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)
895ee682 813{
fea23fb5 814 int delay;
895ee682 815
e1dde8dc 816 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
fea23fb5 817 delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;
e1dde8dc 818 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
fea23fb5 819 delay = MII_M1111_RGMII_RX_DELAY;
e1dde8dc 820 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
fea23fb5
RK
821 delay = MII_M1111_RGMII_TX_DELAY;
822 } else {
823 delay = 0;
e1dde8dc 824 }
895ee682 825
fea23fb5 826 return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
f102852f 827 MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY,
fea23fb5 828 delay);
61111598
AL
829}
830
831static int m88e1111_config_init_rgmii(struct phy_device *phydev)
832{
833 int temp;
834 int err;
835
836 err = m88e1111_config_init_rgmii_delays(phydev);
e1dde8dc
AL
837 if (err < 0)
838 return err;
9daf5a76 839
e1dde8dc
AL
840 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
841 if (temp < 0)
842 return temp;
895ee682 843
e1dde8dc 844 temp &= ~(MII_M1111_HWCFG_MODE_MASK);
be937f1f 845
e1dde8dc
AL
846 if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
847 temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
848 else
849 temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
895ee682 850
e1dde8dc
AL
851 return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
852}
895ee682 853
e1dde8dc
AL
854static int m88e1111_config_init_sgmii(struct phy_device *phydev)
855{
856 int err;
4117b5be 857
865b813a
AL
858 err = m88e1111_config_init_hwcfg_mode(
859 phydev,
860 MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
861 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
e1dde8dc
AL
862 if (err < 0)
863 return err;
07151bc9 864
e1dde8dc 865 /* make sure copper is selected */
52295666 866 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
e1dde8dc 867}
5f8cbc13 868
e1dde8dc
AL
869static int m88e1111_config_init_rtbi(struct phy_device *phydev)
870{
61111598 871 int err;
e1dde8dc 872
61111598 873 err = m88e1111_config_init_rgmii_delays(phydev);
fea23fb5 874 if (err < 0)
e1dde8dc
AL
875 return err;
876
865b813a
AL
877 err = m88e1111_config_init_hwcfg_mode(
878 phydev,
879 MII_M1111_HWCFG_MODE_RTBI,
880 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
e1dde8dc
AL
881 if (err < 0)
882 return err;
883
884 /* soft reset */
34386344 885 err = genphy_soft_reset(phydev);
e1dde8dc
AL
886 if (err < 0)
887 return err;
888
865b813a
AL
889 return m88e1111_config_init_hwcfg_mode(
890 phydev,
891 MII_M1111_HWCFG_MODE_RTBI,
892 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
e1dde8dc
AL
893}
894
1887023a
RH
895static int m88e1111_config_init_1000basex(struct phy_device *phydev)
896{
897 int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
898 int err, mode;
899
900 if (extsr < 0)
901 return extsr;
902
903 /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */
904 mode = extsr & MII_M1111_HWCFG_MODE_MASK;
905 if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) {
906 err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
907 MII_M1111_HWCFG_MODE_MASK |
908 MII_M1111_HWCFG_SERIAL_AN_BYPASS,
909 MII_M1111_HWCFG_MODE_COPPER_1000X_AN |
910 MII_M1111_HWCFG_SERIAL_AN_BYPASS);
911 if (err < 0)
912 return err;
913 }
914 return 0;
915}
916
e1dde8dc
AL
917static int m88e1111_config_init(struct phy_device *phydev)
918{
919 int err;
920
921 if (phy_interface_is_rgmii(phydev)) {
922 err = m88e1111_config_init_rgmii(phydev);
fea23fb5 923 if (err < 0)
5f8cbc13 924 return err;
e1dde8dc 925 }
5f8cbc13 926
e1dde8dc
AL
927 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
928 err = m88e1111_config_init_sgmii(phydev);
5f8cbc13
LYB
929 if (err < 0)
930 return err;
e1dde8dc 931 }
5f8cbc13 932
e1dde8dc
AL
933 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
934 err = m88e1111_config_init_rtbi(phydev);
5f8cbc13
LYB
935 if (err < 0)
936 return err;
937 }
938
1887023a
RH
939 if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) {
940 err = m88e1111_config_init_1000basex(phydev);
941 if (err < 0)
942 return err;
943 }
944
cf41a51d
DD
945 err = marvell_of_reg_init(phydev);
946 if (err < 0)
947 return err;
5f8cbc13 948
34386344 949 return genphy_soft_reset(phydev);
895ee682
KP
950}
951
5c6bc519
HK
952static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)
953{
954 int val, cnt, enable;
955
956 val = phy_read(phydev, MII_M1111_PHY_EXT_CR);
957 if (val < 0)
958 return val;
959
960 enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val);
961 cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1;
962
963 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
964
965 return 0;
966}
967
968static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)
969{
970 int val;
971
972 if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX)
973 return -E2BIG;
974
975 if (!cnt)
976 return phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,
977 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);
978
979 val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;
980 val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);
981
982 return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
983 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |
984 MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,
985 val);
986}
987
988static int m88e1111_get_tunable(struct phy_device *phydev,
989 struct ethtool_tunable *tuna, void *data)
990{
991 switch (tuna->id) {
992 case ETHTOOL_PHY_DOWNSHIFT:
993 return m88e1111_get_downshift(phydev, data);
994 default:
995 return -EOPNOTSUPP;
996 }
997}
998
999static int m88e1111_set_tunable(struct phy_device *phydev,
1000 struct ethtool_tunable *tuna, const void *data)
1001{
1002 switch (tuna->id) {
1003 case ETHTOOL_PHY_DOWNSHIFT:
1004 return m88e1111_set_downshift(phydev, *(const u8 *)data);
1005 default:
1006 return -EOPNOTSUPP;
1007 }
1008}
1009
911af5e1 1010static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data)
a3bdfce7
HK
1011{
1012 int val, cnt, enable;
1013
1014 val = phy_read(phydev, MII_M1011_PHY_SCR);
1015 if (val < 0)
1016 return val;
1017
1018 enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val);
f8d975be 1019 cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1;
a3bdfce7
HK
1020
1021 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
1022
1023 return 0;
1024}
1025
911af5e1 1026static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt)
a3bdfce7
HK
1027{
1028 int val;
1029
1030 if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)
1031 return -E2BIG;
1032
1033 if (!cnt)
1034 return phy_clear_bits(phydev, MII_M1011_PHY_SCR,
1035 MII_M1011_PHY_SCR_DOWNSHIFT_EN);
1036
1037 val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;
f8d975be 1038 val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);
a3bdfce7
HK
1039
1040 return phy_modify(phydev, MII_M1011_PHY_SCR,
1041 MII_M1011_PHY_SCR_DOWNSHIFT_EN |
f8d975be 1042 MII_M1011_PHY_SCR_DOWNSHIFT_MASK,
a3bdfce7
HK
1043 val);
1044}
1045
911af5e1 1046static int m88e1011_get_tunable(struct phy_device *phydev,
a3bdfce7
HK
1047 struct ethtool_tunable *tuna, void *data)
1048{
1049 switch (tuna->id) {
1050 case ETHTOOL_PHY_DOWNSHIFT:
911af5e1 1051 return m88e1011_get_downshift(phydev, data);
a3bdfce7
HK
1052 default:
1053 return -EOPNOTSUPP;
1054 }
1055}
1056
911af5e1 1057static int m88e1011_set_tunable(struct phy_device *phydev,
a3bdfce7
HK
1058 struct ethtool_tunable *tuna, const void *data)
1059{
1060 switch (tuna->id) {
1061 case ETHTOOL_PHY_DOWNSHIFT:
911af5e1 1062 return m88e1011_set_downshift(phydev, *(const u8 *)data);
a3bdfce7
HK
1063 default:
1064 return -EOPNOTSUPP;
1065 }
1066}
1067
e2d861cc
HK
1068static int m88e1116r_config_init(struct phy_device *phydev)
1069{
1070 int err;
1071
1072 err = genphy_soft_reset(phydev);
1073 if (err < 0)
1074 return err;
1075
1076 msleep(500);
1077
1078 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
1079 if (err < 0)
1080 return err;
1081
1082 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
1083 if (err < 0)
1084 return err;
1085
911af5e1 1086 err = m88e1011_set_downshift(phydev, 8);
e2d861cc
HK
1087 if (err < 0)
1088 return err;
1089
1090 if (phy_interface_is_rgmii(phydev)) {
1091 err = m88e1121_config_aneg_rgmii_delays(phydev);
1092 if (err < 0)
1093 return err;
1094 }
1095
1096 err = genphy_soft_reset(phydev);
1097 if (err < 0)
1098 return err;
1099
1100 return marvell_config_init(phydev);
1101}
1102
dd9a122a
EH
1103static int m88e1318_config_init(struct phy_device *phydev)
1104{
1105 if (phy_interrupt_is_valid(phydev)) {
1106 int err = phy_modify_paged(
1107 phydev, MII_MARVELL_LED_PAGE,
1108 MII_88E1318S_PHY_LED_TCR,
1109 MII_88E1318S_PHY_LED_TCR_FORCE_INT,
1110 MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
1111 MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
1112 if (err < 0)
1113 return err;
1114 }
1115
07777246 1116 return marvell_config_init(phydev);
dd9a122a
EH
1117}
1118
407353ec
CG
1119static int m88e1510_config_init(struct phy_device *phydev)
1120{
1121 int err;
407353ec
CG
1122
1123 /* SGMII-to-Copper mode initialization */
1124 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
1125 /* Select page 18 */
6427bb2d 1126 err = marvell_set_page(phydev, 18);
407353ec
CG
1127 if (err < 0)
1128 return err;
1129
1130 /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
fea23fb5 1131 err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
f102852f 1132 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,
fea23fb5 1133 MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII);
407353ec
CG
1134 if (err < 0)
1135 return err;
1136
1137 /* PHY reset is necessary after changing MODE[2:0] */
832913c3
YD
1138 err = phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,
1139 MII_88E1510_GEN_CTRL_REG_1_RESET);
407353ec
CG
1140 if (err < 0)
1141 return err;
1142
1143 /* Reset page selection */
52295666 1144 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
407353ec
CG
1145 if (err < 0)
1146 return err;
1147 }
1148
dd9a122a 1149 return m88e1318_config_init(phydev);
407353ec
CG
1150}
1151
605f196e
RM
1152static int m88e1118_config_aneg(struct phy_device *phydev)
1153{
1154 int err;
1155
34386344 1156 err = genphy_soft_reset(phydev);
605f196e
RM
1157 if (err < 0)
1158 return err;
1159
fecd5e91 1160 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
605f196e
RM
1161 if (err < 0)
1162 return err;
1163
1164 err = genphy_config_aneg(phydev);
1165 return 0;
1166}
1167
1168static int m88e1118_config_init(struct phy_device *phydev)
1169{
1170 int err;
1171
1172 /* Change address */
52295666 1173 err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
605f196e
RM
1174 if (err < 0)
1175 return err;
1176
1177 /* Enable 1000 Mbit */
1178 err = phy_write(phydev, 0x15, 0x1070);
1179 if (err < 0)
1180 return err;
1181
1182 /* Change address */
52295666 1183 err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE);
605f196e
RM
1184 if (err < 0)
1185 return err;
1186
1187 /* Adjust LED Control */
2f495c39
BH
1188 if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
1189 err = phy_write(phydev, 0x10, 0x1100);
1190 else
1191 err = phy_write(phydev, 0x10, 0x021e);
605f196e
RM
1192 if (err < 0)
1193 return err;
1194
cf41a51d
DD
1195 err = marvell_of_reg_init(phydev);
1196 if (err < 0)
1197 return err;
1198
605f196e 1199 /* Reset address */
52295666 1200 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
605f196e
RM
1201 if (err < 0)
1202 return err;
1203
34386344 1204 return genphy_soft_reset(phydev);
605f196e
RM
1205}
1206
90600732
DD
1207static int m88e1149_config_init(struct phy_device *phydev)
1208{
1209 int err;
1210
1211 /* Change address */
52295666 1212 err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
90600732
DD
1213 if (err < 0)
1214 return err;
1215
1216 /* Enable 1000 Mbit */
1217 err = phy_write(phydev, 0x15, 0x1048);
1218 if (err < 0)
1219 return err;
1220
cf41a51d
DD
1221 err = marvell_of_reg_init(phydev);
1222 if (err < 0)
1223 return err;
1224
90600732 1225 /* Reset address */
52295666 1226 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
90600732
DD
1227 if (err < 0)
1228 return err;
1229
34386344 1230 return genphy_soft_reset(phydev);
90600732
DD
1231}
1232
e1dde8dc
AL
1233static int m88e1145_config_init_rgmii(struct phy_device *phydev)
1234{
1235 int err;
e1dde8dc 1236
61111598 1237 err = m88e1111_config_init_rgmii_delays(phydev);
e1dde8dc
AL
1238 if (err < 0)
1239 return err;
1240
1241 if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
1242 err = phy_write(phydev, 0x1d, 0x0012);
1243 if (err < 0)
1244 return err;
1245
f102852f 1246 err = phy_modify(phydev, 0x1e, 0x0fc0,
fea23fb5
RK
1247 2 << 9 | /* 36 ohm */
1248 2 << 6); /* 39 ohm */
e1dde8dc
AL
1249 if (err < 0)
1250 return err;
1251
1252 err = phy_write(phydev, 0x1d, 0x3);
1253 if (err < 0)
1254 return err;
1255
1256 err = phy_write(phydev, 0x1e, 0x8000);
1257 }
1258 return err;
1259}
1260
1261static int m88e1145_config_init_sgmii(struct phy_device *phydev)
1262{
865b813a
AL
1263 return m88e1111_config_init_hwcfg_mode(
1264 phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
1265 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
e1dde8dc
AL
1266}
1267
76884679
AF
1268static int m88e1145_config_init(struct phy_device *phydev)
1269{
1270 int err;
1271
1272 /* Take care of errata E0 & E1 */
1273 err = phy_write(phydev, 0x1d, 0x001b);
1274 if (err < 0)
1275 return err;
1276
1277 err = phy_write(phydev, 0x1e, 0x418f);
1278 if (err < 0)
1279 return err;
1280
1281 err = phy_write(phydev, 0x1d, 0x0016);
1282 if (err < 0)
1283 return err;
1284
1285 err = phy_write(phydev, 0x1e, 0xa2da);
1286 if (err < 0)
1287 return err;
1288
895ee682 1289 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
e1dde8dc 1290 err = m88e1145_config_init_rgmii(phydev);
76884679
AF
1291 if (err < 0)
1292 return err;
76884679
AF
1293 }
1294
b0224175 1295 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
e1dde8dc 1296 err = m88e1145_config_init_sgmii(phydev);
b0224175
VND
1297 if (err < 0)
1298 return err;
1299 }
1300
cf41a51d
DD
1301 err = marvell_of_reg_init(phydev);
1302 if (err < 0)
1303 return err;
1304
76884679
AF
1305 return 0;
1306}
00db8189 1307
69f42be8
HK
1308static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)
1309{
1310 int val;
1311
1312 val = phy_read(phydev, MII_88E1540_COPPER_CTRL3);
1313 if (val < 0)
1314 return val;
1315
1316 if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) {
1317 *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
1318 return 0;
1319 }
1320
1321 val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
1322
1323 switch (val) {
1324 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS:
1325 *msecs = 0;
1326 break;
1327 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS:
1328 *msecs = 10;
1329 break;
1330 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS:
1331 *msecs = 20;
1332 break;
1333 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS:
1334 *msecs = 40;
1335 break;
1336 default:
1337 return -EINVAL;
1338 }
1339
1340 return 0;
1341}
1342
1343static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)
1344{
1345 struct ethtool_eee eee;
1346 int val, ret;
1347
1348 if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
1349 return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3,
1350 MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
1351
1352 /* According to the Marvell data sheet EEE must be disabled for
1353 * Fast Link Down detection to work properly
1354 */
1355 ret = phy_ethtool_get_eee(phydev, &eee);
1356 if (!ret && eee.eee_enabled) {
1357 phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");
1358 return -EBUSY;
1359 }
1360
1361 if (*msecs <= 5)
1362 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS;
1363 else if (*msecs <= 15)
1364 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS;
1365 else if (*msecs <= 30)
1366 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS;
1367 else
1368 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS;
1369
1370 val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
1371
1372 ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3,
1373 MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
1374 if (ret)
1375 return ret;
1376
1377 return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3,
1378 MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
1379}
1380
1381static int m88e1540_get_tunable(struct phy_device *phydev,
1382 struct ethtool_tunable *tuna, void *data)
1383{
1384 switch (tuna->id) {
1385 case ETHTOOL_PHY_FAST_LINK_DOWN:
1386 return m88e1540_get_fld(phydev, data);
a3bdfce7 1387 case ETHTOOL_PHY_DOWNSHIFT:
911af5e1 1388 return m88e1011_get_downshift(phydev, data);
69f42be8
HK
1389 default:
1390 return -EOPNOTSUPP;
1391 }
1392}
1393
1394static int m88e1540_set_tunable(struct phy_device *phydev,
1395 struct ethtool_tunable *tuna, const void *data)
1396{
1397 switch (tuna->id) {
1398 case ETHTOOL_PHY_FAST_LINK_DOWN:
1399 return m88e1540_set_fld(phydev, data);
a3bdfce7 1400 case ETHTOOL_PHY_DOWNSHIFT:
911af5e1 1401 return m88e1011_set_downshift(phydev, *(const u8 *)data);
69f42be8
HK
1402 default:
1403 return -EOPNOTSUPP;
1404 }
1405}
1406
8cbcdc1a
AL
1407/* The VOD can be out of specification on link up. Poke an
1408 * undocumented register, in an undocumented page, with a magic value
1409 * to fix this.
1410 */
1411static int m88e6390_errata(struct phy_device *phydev)
1412{
1413 int err;
1414
1415 err = phy_write(phydev, MII_BMCR,
1416 BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX);
1417 if (err)
1418 return err;
1419
1420 usleep_range(300, 400);
1421
1422 err = phy_write_paged(phydev, 0xf8, 0x08, 0x36);
1423 if (err)
1424 return err;
1425
1426 return genphy_soft_reset(phydev);
1427}
1428
1429static int m88e6390_config_aneg(struct phy_device *phydev)
1430{
1431 int err;
1432
1433 err = m88e6390_errata(phydev);
1434 if (err)
1435 return err;
1436
1437 return m88e1510_config_aneg(phydev);
1438}
1439
6cfb3bcc 1440/**
ab9cb729 1441 * fiber_lpa_mod_linkmode_lpa_t
c0ec3c27 1442 * @advertising: the linkmode advertisement settings
6cfb3bcc
CAC
1443 * @lpa: value of the MII_LPA register for fiber link
1444 *
ab9cb729
AL
1445 * A small helper function that translates MII_LPA bits to linkmode LP
1446 * advertisement settings. Other bits in advertising are left
1447 * unchanged.
6cfb3bcc 1448 */
ab9cb729 1449static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa)
6cfb3bcc 1450{
ab9cb729 1451 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
20ecf424 1452 advertising, lpa & LPA_1000XHALF);
ab9cb729
AL
1453
1454 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
20ecf424 1455 advertising, lpa & LPA_1000XFULL);
6cfb3bcc
CAC
1456}
1457
e1dde8dc 1458static int marvell_read_status_page_an(struct phy_device *phydev,
d2004e27 1459 int fiber, int status)
e1dde8dc 1460{
e1dde8dc 1461 int lpa;
fcf1f59a 1462 int err;
e1dde8dc 1463
3b72f84f
CG
1464 if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) {
1465 phydev->link = 0;
1466 return 0;
1467 }
1468
1469 if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
1470 phydev->duplex = DUPLEX_FULL;
1471 else
1472 phydev->duplex = DUPLEX_HALF;
1473
1474 switch (status & MII_M1011_PHY_STATUS_SPD_MASK) {
1475 case MII_M1011_PHY_STATUS_1000:
1476 phydev->speed = SPEED_1000;
1477 break;
1478
1479 case MII_M1011_PHY_STATUS_100:
1480 phydev->speed = SPEED_100;
1481 break;
1482
1483 default:
1484 phydev->speed = SPEED_10;
1485 break;
1486 }
1487
e1dde8dc 1488 if (!fiber) {
fcf1f59a
RK
1489 err = genphy_read_lpa(phydev);
1490 if (err < 0)
1491 return err;
e1dde8dc 1492
af006240 1493 phy_resolve_aneg_pause(phydev);
e1dde8dc 1494 } else {
fcf1f59a
RK
1495 lpa = phy_read(phydev, MII_LPA);
1496 if (lpa < 0)
1497 return lpa;
1498
e1dde8dc 1499 /* The fiber link is only 1000M capable */
ab9cb729 1500 fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
e1dde8dc
AL
1501
1502 if (phydev->duplex == DUPLEX_FULL) {
1503 if (!(lpa & LPA_PAUSE_FIBER)) {
1504 phydev->pause = 0;
1505 phydev->asym_pause = 0;
1506 } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) {
1507 phydev->pause = 1;
1508 phydev->asym_pause = 1;
1509 } else {
1510 phydev->pause = 1;
1511 phydev->asym_pause = 0;
1512 }
1513 }
1514 }
fcf1f59a 1515
e1dde8dc
AL
1516 return 0;
1517}
1518
6cfb3bcc 1519/* marvell_read_status_page
be937f1f 1520 *
f0c88f9c 1521 * Description:
be937f1f
AS
1522 * Check the link, then figure out the current state
1523 * by comparing what we advertise with what the link partner
1524 * advertises. Start by checking the gigabit possibilities,
1525 * then move on to 10/100.
1526 */
6cfb3bcc 1527static int marvell_read_status_page(struct phy_device *phydev, int page)
be937f1f 1528{
d2004e27 1529 int status;
6cfb3bcc 1530 int fiber;
e1dde8dc 1531 int err;
be937f1f 1532
d2004e27
RK
1533 status = phy_read(phydev, MII_M1011_PHY_STATUS);
1534 if (status < 0)
1535 return status;
1536
1537 /* Use the generic register for copper link status,
1538 * and the PHY status register for fiber link status.
0c3439bc 1539 */
d2004e27
RK
1540 if (page == MII_MARVELL_FIBER_PAGE) {
1541 phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK);
1542 } else {
1543 err = genphy_update_link(phydev);
1544 if (err)
1545 return err;
1546 }
1547
52295666 1548 if (page == MII_MARVELL_FIBER_PAGE)
6cfb3bcc
CAC
1549 fiber = 1;
1550 else
1551 fiber = 0;
1552
98f92831
RK
1553 linkmode_zero(phydev->lp_advertising);
1554 phydev->pause = 0;
1555 phydev->asym_pause = 0;
b82cf17f
RK
1556 phydev->speed = SPEED_UNKNOWN;
1557 phydev->duplex = DUPLEX_UNKNOWN;
4217a64e 1558 phydev->port = fiber ? PORT_FIBRE : PORT_TP;
98f92831 1559
e1dde8dc 1560 if (phydev->autoneg == AUTONEG_ENABLE)
d2004e27 1561 err = marvell_read_status_page_an(phydev, fiber, status);
e1dde8dc 1562 else
98f92831 1563 err = genphy_read_status_fixed(phydev);
be937f1f 1564
e1dde8dc 1565 return err;
be937f1f
AS
1566}
1567
6cfb3bcc
CAC
1568/* marvell_read_status
1569 *
1570 * Some Marvell's phys have two modes: fiber and copper.
1571 * Both need status checked.
1572 * Description:
1573 * First, check the fiber link and status.
1574 * If the fiber link is down, check the copper link and status which
1575 * will be the default value if both link are down.
1576 */
1577static int marvell_read_status(struct phy_device *phydev)
1578{
1579 int err;
1580
1581 /* Check the fiber mode first */
3c1bcc86
AL
1582 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1583 phydev->supported) &&
a13c0652 1584 phydev->interface != PHY_INTERFACE_MODE_SGMII) {
52295666 1585 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
6cfb3bcc
CAC
1586 if (err < 0)
1587 goto error;
1588
52295666 1589 err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE);
6cfb3bcc
CAC
1590 if (err < 0)
1591 goto error;
1592
0c3439bc
AL
1593 /* If the fiber link is up, it is the selected and
1594 * used link. In this case, we need to stay in the
1595 * fiber page. Please to be careful about that, avoid
1596 * to restore Copper page in other functions which
1597 * could break the behaviour for some fiber phy like
1598 * 88E1512.
1599 */
6cfb3bcc
CAC
1600 if (phydev->link)
1601 return 0;
1602
1603 /* If fiber link is down, check and save copper mode state */
52295666 1604 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
6cfb3bcc
CAC
1605 if (err < 0)
1606 goto error;
1607 }
1608
52295666 1609 return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE);
6cfb3bcc
CAC
1610
1611error:
52295666 1612 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
6cfb3bcc
CAC
1613 return err;
1614}
3758be3d
CAC
1615
1616/* marvell_suspend
1617 *
1618 * Some Marvell's phys have two modes: fiber and copper.
1619 * Both need to be suspended
1620 */
1621static int marvell_suspend(struct phy_device *phydev)
1622{
1623 int err;
1624
1625 /* Suspend the fiber mode first */
3c1bcc86
AL
1626 if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1627 phydev->supported)) {
52295666 1628 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
3758be3d
CAC
1629 if (err < 0)
1630 goto error;
1631
1632 /* With the page set, use the generic suspend */
1633 err = genphy_suspend(phydev);
1634 if (err < 0)
1635 goto error;
1636
1637 /* Then, the copper link */
52295666 1638 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
3758be3d
CAC
1639 if (err < 0)
1640 goto error;
1641 }
1642
1643 /* With the page set, use the generic suspend */
1644 return genphy_suspend(phydev);
1645
1646error:
52295666 1647 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
3758be3d
CAC
1648 return err;
1649}
1650
1651/* marvell_resume
1652 *
1653 * Some Marvell's phys have two modes: fiber and copper.
1654 * Both need to be resumed
1655 */
1656static int marvell_resume(struct phy_device *phydev)
1657{
1658 int err;
1659
1660 /* Resume the fiber mode first */
3c1bcc86
AL
1661 if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1662 phydev->supported)) {
52295666 1663 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
3758be3d
CAC
1664 if (err < 0)
1665 goto error;
1666
1667 /* With the page set, use the generic resume */
1668 err = genphy_resume(phydev);
1669 if (err < 0)
1670 goto error;
1671
1672 /* Then, the copper link */
52295666 1673 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
3758be3d
CAC
1674 if (err < 0)
1675 goto error;
1676 }
1677
1678 /* With the page set, use the generic resume */
1679 return genphy_resume(phydev);
1680
1681error:
52295666 1682 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
3758be3d
CAC
1683 return err;
1684}
1685
6b358aed
SH
1686static int marvell_aneg_done(struct phy_device *phydev)
1687{
1688 int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
e69d9ed4 1689
6b358aed
SH
1690 return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
1691}
1692
23beb38f
AL
1693static void m88e1318_get_wol(struct phy_device *phydev,
1694 struct ethtool_wolinfo *wol)
3871c387 1695{
f4f9dcc3 1696 int ret;
424ca4c5 1697
3871c387
MS
1698 wol->supported = WAKE_MAGIC;
1699 wol->wolopts = 0;
1700
f4f9dcc3
JZ
1701 ret = phy_read_paged(phydev, MII_MARVELL_WOL_PAGE,
1702 MII_88E1318S_PHY_WOL_CTRL);
1703 if (ret >= 0 && ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
3871c387 1704 wol->wolopts |= WAKE_MAGIC;
3871c387
MS
1705}
1706
23beb38f
AL
1707static int m88e1318_set_wol(struct phy_device *phydev,
1708 struct ethtool_wolinfo *wol)
3871c387 1709{
424ca4c5 1710 int err = 0, oldpage;
3871c387 1711
424ca4c5
RK
1712 oldpage = phy_save_page(phydev);
1713 if (oldpage < 0)
1714 goto error;
3871c387
MS
1715
1716 if (wol->wolopts & WAKE_MAGIC) {
1717 /* Explicitly switch to page 0x00, just to be sure */
424ca4c5 1718 err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
3871c387 1719 if (err < 0)
424ca4c5 1720 goto error;
3871c387 1721
b6a930fa
JH
1722 /* If WOL event happened once, the LED[2] interrupt pin
1723 * will not be cleared unless we reading the interrupt status
1724 * register. If interrupts are in use, the normal interrupt
1725 * handling will clear the WOL event. Clear the WOL event
1726 * before enabling it if !phy_interrupt_is_valid()
1727 */
1728 if (!phy_interrupt_is_valid(phydev))
e0a7328f 1729 __phy_read(phydev, MII_M1011_IEVENT);
b6a930fa 1730
3871c387 1731 /* Enable the WOL interrupt */
832913c3
YD
1732 err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER,
1733 MII_88E1318S_PHY_CSIER_WOL_EIE);
3871c387 1734 if (err < 0)
424ca4c5 1735 goto error;
3871c387 1736
424ca4c5 1737 err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);
3871c387 1738 if (err < 0)
424ca4c5 1739 goto error;
3871c387
MS
1740
1741 /* Setup LED[2] as interrupt pin (active low) */
424ca4c5 1742 err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR,
f102852f 1743 MII_88E1318S_PHY_LED_TCR_FORCE_INT,
424ca4c5
RK
1744 MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
1745 MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
3871c387 1746 if (err < 0)
424ca4c5 1747 goto error;
3871c387 1748
424ca4c5 1749 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
3871c387 1750 if (err < 0)
424ca4c5 1751 goto error;
3871c387
MS
1752
1753 /* Store the device address for the magic packet */
424ca4c5 1754 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
3871c387
MS
1755 ((phydev->attached_dev->dev_addr[5] << 8) |
1756 phydev->attached_dev->dev_addr[4]));
1757 if (err < 0)
424ca4c5
RK
1758 goto error;
1759 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
3871c387
MS
1760 ((phydev->attached_dev->dev_addr[3] << 8) |
1761 phydev->attached_dev->dev_addr[2]));
1762 if (err < 0)
424ca4c5
RK
1763 goto error;
1764 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
3871c387
MS
1765 ((phydev->attached_dev->dev_addr[1] << 8) |
1766 phydev->attached_dev->dev_addr[0]));
1767 if (err < 0)
424ca4c5 1768 goto error;
3871c387
MS
1769
1770 /* Clear WOL status and enable magic packet matching */
832913c3
YD
1771 err = __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL,
1772 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |
1773 MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE);
3871c387 1774 if (err < 0)
424ca4c5 1775 goto error;
3871c387 1776 } else {
424ca4c5 1777 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
3871c387 1778 if (err < 0)
424ca4c5 1779 goto error;
3871c387
MS
1780
1781 /* Clear WOL status and disable magic packet matching */
424ca4c5 1782 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,
f102852f 1783 MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE,
424ca4c5 1784 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);
3871c387 1785 if (err < 0)
424ca4c5 1786 goto error;
3871c387
MS
1787 }
1788
424ca4c5
RK
1789error:
1790 return phy_restore_page(phydev, oldpage, err);
3871c387
MS
1791}
1792
d2fa47d9
AL
1793static int marvell_get_sset_count(struct phy_device *phydev)
1794{
3c1bcc86
AL
1795 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1796 phydev->supported))
2170fef7
CAC
1797 return ARRAY_SIZE(marvell_hw_stats);
1798 else
1799 return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;
d2fa47d9
AL
1800}
1801
1802static void marvell_get_strings(struct phy_device *phydev, u8 *data)
1803{
fdfdf867 1804 int count = marvell_get_sset_count(phydev);
d2fa47d9
AL
1805 int i;
1806
fdfdf867 1807 for (i = 0; i < count; i++) {
98409b2b
FF
1808 strlcpy(data + i * ETH_GSTRING_LEN,
1809 marvell_hw_stats[i].string, ETH_GSTRING_LEN);
d2fa47d9
AL
1810 }
1811}
1812
d2fa47d9
AL
1813static u64 marvell_get_stat(struct phy_device *phydev, int i)
1814{
1815 struct marvell_hw_stat stat = marvell_hw_stats[i];
1816 struct marvell_priv *priv = phydev->priv;
424ca4c5 1817 int val;
321b4d4b 1818 u64 ret;
d2fa47d9 1819
424ca4c5 1820 val = phy_read_paged(phydev, stat.page, stat.reg);
d2fa47d9 1821 if (val < 0) {
6c3442f5 1822 ret = U64_MAX;
d2fa47d9
AL
1823 } else {
1824 val = val & ((1 << stat.bits) - 1);
1825 priv->stats[i] += val;
321b4d4b 1826 ret = priv->stats[i];
d2fa47d9
AL
1827 }
1828
321b4d4b 1829 return ret;
d2fa47d9
AL
1830}
1831
1832static void marvell_get_stats(struct phy_device *phydev,
1833 struct ethtool_stats *stats, u64 *data)
1834{
fdfdf867 1835 int count = marvell_get_sset_count(phydev);
d2fa47d9
AL
1836 int i;
1837
fdfdf867 1838 for (i = 0; i < count; i++)
d2fa47d9
AL
1839 data[i] = marvell_get_stat(phydev, i);
1840}
1841
0c9bcc1d
AL
1842static int marvell_vct5_wait_complete(struct phy_device *phydev)
1843{
1844 int i;
1845 int val;
1846
1847 for (i = 0; i < 32; i++) {
a618e86d 1848 val = __phy_read(phydev, MII_VCT5_CTRL);
0c9bcc1d
AL
1849 if (val < 0)
1850 return val;
1851
1852 if (val & MII_VCT5_CTRL_COMPLETE)
1853 return 0;
0c9bcc1d
AL
1854 }
1855
1856 phydev_err(phydev, "Timeout while waiting for cable test to finish\n");
1857 return -ETIMEDOUT;
1858}
1859
1860static int marvell_vct5_amplitude(struct phy_device *phydev, int pair)
1861{
1862 int amplitude;
1863 int val;
1864 int reg;
1865
1866 reg = MII_VCT5_TX_RX_MDI0_COUPLING + pair;
a618e86d 1867 val = __phy_read(phydev, reg);
0c9bcc1d
AL
1868
1869 if (val < 0)
1870 return 0;
1871
1872 amplitude = (val & MII_VCT5_TX_RX_AMPLITUDE_MASK) >>
1873 MII_VCT5_TX_RX_AMPLITUDE_SHIFT;
1874
1875 if (!(val & MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION))
1876 amplitude = -amplitude;
1877
1878 return 1000 * amplitude / 128;
1879}
1880
1881static u32 marvell_vct5_distance2cm(int distance)
1882{
1883 return distance * 805 / 10;
1884}
1885
f2bc8ad3
AL
1886static u32 marvell_vct5_cm2distance(int cm)
1887{
1888 return cm * 10 / 805;
1889}
1890
0c9bcc1d 1891static int marvell_vct5_amplitude_distance(struct phy_device *phydev,
f2bc8ad3 1892 int distance, int pair)
0c9bcc1d 1893{
0c9bcc1d
AL
1894 u16 reg;
1895 int err;
f2bc8ad3
AL
1896 int mV;
1897 int i;
0c9bcc1d 1898
a618e86d
AL
1899 err = __phy_write(phydev, MII_VCT5_SAMPLE_POINT_DISTANCE,
1900 distance);
0c9bcc1d
AL
1901 if (err)
1902 return err;
1903
1904 reg = MII_VCT5_CTRL_ENABLE |
1905 MII_VCT5_CTRL_TX_SAME_CHANNEL |
1906 MII_VCT5_CTRL_SAMPLES_DEFAULT |
1907 MII_VCT5_CTRL_SAMPLE_POINT |
1908 MII_VCT5_CTRL_PEEK_HYST_DEFAULT;
a618e86d 1909 err = __phy_write(phydev, MII_VCT5_CTRL, reg);
0c9bcc1d
AL
1910 if (err)
1911 return err;
1912
1913 err = marvell_vct5_wait_complete(phydev);
1914 if (err)
1915 return err;
1916
f2bc8ad3
AL
1917 for (i = 0; i < 4; i++) {
1918 if (pair != PHY_PAIR_ALL && i != pair)
1919 continue;
0c9bcc1d 1920
f2bc8ad3
AL
1921 mV = marvell_vct5_amplitude(phydev, i);
1922 ethnl_cable_test_amplitude(phydev, i, mV);
1923 }
0c9bcc1d
AL
1924
1925 return 0;
1926}
1927
1928static int marvell_vct5_amplitude_graph(struct phy_device *phydev)
1929{
f2bc8ad3 1930 struct marvell_priv *priv = phydev->priv;
0c9bcc1d 1931 int distance;
db8668a1 1932 u16 width;
a618e86d 1933 int page;
0c9bcc1d
AL
1934 int err;
1935 u16 reg;
1936
db8668a1
AL
1937 if (priv->first <= TDR_SHORT_CABLE_LENGTH)
1938 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS;
1939 else
1940 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;
1941
0c9bcc1d
AL
1942 reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |
1943 MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |
db8668a1 1944 MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;
0c9bcc1d
AL
1945
1946 err = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,
1947 MII_VCT5_TX_PULSE_CTRL, reg);
1948 if (err)
1949 return err;
1950
a618e86d
AL
1951 /* Reading the TDR data is very MDIO heavy. We need to optimize
1952 * access to keep the time to a minimum. So lock the bus once,
1953 * and don't release it until complete. We can then avoid having
1954 * to change the page for every access, greatly speeding things
1955 * up.
1956 */
1957 page = phy_select_page(phydev, MII_MARVELL_VCT5_PAGE);
1958 if (page < 0)
830f5ce2 1959 goto restore_page;
a618e86d 1960
f2bc8ad3
AL
1961 for (distance = priv->first;
1962 distance <= priv->last;
1963 distance += priv->step) {
1964 err = marvell_vct5_amplitude_distance(phydev, distance,
1965 priv->pair);
0c9bcc1d 1966 if (err)
a618e86d 1967 goto restore_page;
db8668a1
AL
1968
1969 if (distance > TDR_SHORT_CABLE_LENGTH &&
1970 width == MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS) {
1971 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;
1972 reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |
1973 MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |
1974 MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;
1975 err = __phy_write(phydev, MII_VCT5_TX_PULSE_CTRL, reg);
1976 if (err)
1977 goto restore_page;
1978 }
0c9bcc1d
AL
1979 }
1980
a618e86d
AL
1981restore_page:
1982 return phy_restore_page(phydev, page, err);
0c9bcc1d
AL
1983}
1984
1985static int marvell_cable_test_start_common(struct phy_device *phydev)
fc879f72
AL
1986{
1987 int bmcr, bmsr, ret;
1988
1989 /* If auto-negotiation is enabled, but not complete, the cable
1990 * test never completes. So disable auto-neg.
1991 */
1992 bmcr = phy_read(phydev, MII_BMCR);
1993 if (bmcr < 0)
1994 return bmcr;
1995
1996 bmsr = phy_read(phydev, MII_BMSR);
1997
1998 if (bmsr < 0)
1999 return bmsr;
2000
2001 if (bmcr & BMCR_ANENABLE) {
832913c3 2002 ret = phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE);
fc879f72
AL
2003 if (ret < 0)
2004 return ret;
2005 ret = genphy_soft_reset(phydev);
2006 if (ret < 0)
2007 return ret;
2008 }
2009
2010 /* If the link is up, allow it some time to go down */
2011 if (bmsr & BMSR_LSTATUS)
2012 msleep(1500);
2013
0c9bcc1d
AL
2014 return 0;
2015}
2016
2017static int marvell_vct7_cable_test_start(struct phy_device *phydev)
2018{
2019 struct marvell_priv *priv = phydev->priv;
2020 int ret;
2021
2022 ret = marvell_cable_test_start_common(phydev);
2023 if (ret)
2024 return ret;
2025
2026 priv->cable_test_tdr = false;
2027
2028 /* Reset the VCT5 API control to defaults, otherwise
2029 * VCT7 does not work correctly.
2030 */
2031 ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,
2032 MII_VCT5_CTRL,
2033 MII_VCT5_CTRL_TX_SAME_CHANNEL |
2034 MII_VCT5_CTRL_SAMPLES_DEFAULT |
2035 MII_VCT5_CTRL_MODE_MAXIMUM_PEEK |
2036 MII_VCT5_CTRL_PEEK_HYST_DEFAULT);
2037 if (ret)
2038 return ret;
2039
2040 ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,
2041 MII_VCT5_SAMPLE_POINT_DISTANCE, 0);
2042 if (ret)
2043 return ret;
2044
fc879f72
AL
2045 return phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,
2046 MII_VCT7_CTRL,
2047 MII_VCT7_CTRL_RUN_NOW |
2048 MII_VCT7_CTRL_CENTIMETERS);
2049}
2050
f2bc8ad3
AL
2051static int marvell_vct5_cable_test_tdr_start(struct phy_device *phydev,
2052 const struct phy_tdr_config *cfg)
0c9bcc1d
AL
2053{
2054 struct marvell_priv *priv = phydev->priv;
2055 int ret;
2056
f2bc8ad3
AL
2057 priv->cable_test_tdr = true;
2058 priv->first = marvell_vct5_cm2distance(cfg->first);
2059 priv->last = marvell_vct5_cm2distance(cfg->last);
2060 priv->step = marvell_vct5_cm2distance(cfg->step);
2061 priv->pair = cfg->pair;
2062
2063 if (priv->first > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)
2064 return -EINVAL;
2065
2066 if (priv->last > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)
2067 return -EINVAL;
2068
0c9bcc1d
AL
2069 /* Disable VCT7 */
2070 ret = phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,
2071 MII_VCT7_CTRL, 0);
2072 if (ret)
2073 return ret;
2074
2075 ret = marvell_cable_test_start_common(phydev);
2076 if (ret)
2077 return ret;
2078
0c9bcc1d
AL
2079 ret = ethnl_cable_test_pulse(phydev, 1000);
2080 if (ret)
2081 return ret;
2082
2083 return ethnl_cable_test_step(phydev,
f2bc8ad3
AL
2084 marvell_vct5_distance2cm(priv->first),
2085 marvell_vct5_distance2cm(priv->last),
2086 marvell_vct5_distance2cm(priv->step));
0c9bcc1d
AL
2087}
2088
fc879f72
AL
2089static int marvell_vct7_distance_to_length(int distance, bool meter)
2090{
2091 if (meter)
2092 distance *= 100;
2093
2094 return distance;
2095}
2096
2097static bool marvell_vct7_distance_valid(int result)
2098{
2099 switch (result) {
2100 case MII_VCT7_RESULTS_OPEN:
2101 case MII_VCT7_RESULTS_SAME_SHORT:
2102 case MII_VCT7_RESULTS_CROSS_SHORT:
2103 return true;
2104 }
2105 return false;
2106}
2107
2108static int marvell_vct7_report_length(struct phy_device *phydev,
2109 int pair, bool meter)
2110{
2111 int length;
2112 int ret;
2113
2114 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,
2115 MII_VCT7_PAIR_0_DISTANCE + pair);
2116 if (ret < 0)
2117 return ret;
2118
2119 length = marvell_vct7_distance_to_length(ret, meter);
2120
2121 ethnl_cable_test_fault_length(phydev, pair, length);
2122
2123 return 0;
2124}
2125
2126static int marvell_vct7_cable_test_report_trans(int result)
2127{
2128 switch (result) {
2129 case MII_VCT7_RESULTS_OK:
2130 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
2131 case MII_VCT7_RESULTS_OPEN:
2132 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
2133 case MII_VCT7_RESULTS_SAME_SHORT:
2134 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
2135 case MII_VCT7_RESULTS_CROSS_SHORT:
2136 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
2137 default:
2138 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
2139 }
2140}
2141
2142static int marvell_vct7_cable_test_report(struct phy_device *phydev)
2143{
2144 int pair0, pair1, pair2, pair3;
2145 bool meter;
2146 int ret;
2147
2148 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,
2149 MII_VCT7_RESULTS);
2150 if (ret < 0)
2151 return ret;
2152
2153 pair3 = (ret & MII_VCT7_RESULTS_PAIR3_MASK) >>
2154 MII_VCT7_RESULTS_PAIR3_SHIFT;
2155 pair2 = (ret & MII_VCT7_RESULTS_PAIR2_MASK) >>
2156 MII_VCT7_RESULTS_PAIR2_SHIFT;
2157 pair1 = (ret & MII_VCT7_RESULTS_PAIR1_MASK) >>
2158 MII_VCT7_RESULTS_PAIR1_SHIFT;
2159 pair0 = (ret & MII_VCT7_RESULTS_PAIR0_MASK) >>
2160 MII_VCT7_RESULTS_PAIR0_SHIFT;
2161
2162 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
2163 marvell_vct7_cable_test_report_trans(pair0));
2164 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
2165 marvell_vct7_cable_test_report_trans(pair1));
2166 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
2167 marvell_vct7_cable_test_report_trans(pair2));
2168 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
2169 marvell_vct7_cable_test_report_trans(pair3));
2170
2171 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, MII_VCT7_CTRL);
2172 if (ret < 0)
2173 return ret;
2174
2175 meter = ret & MII_VCT7_CTRL_METERS;
2176
2177 if (marvell_vct7_distance_valid(pair0))
2178 marvell_vct7_report_length(phydev, 0, meter);
2179 if (marvell_vct7_distance_valid(pair1))
2180 marvell_vct7_report_length(phydev, 1, meter);
2181 if (marvell_vct7_distance_valid(pair2))
2182 marvell_vct7_report_length(phydev, 2, meter);
2183 if (marvell_vct7_distance_valid(pair3))
2184 marvell_vct7_report_length(phydev, 3, meter);
2185
2186 return 0;
2187}
2188
2189static int marvell_vct7_cable_test_get_status(struct phy_device *phydev,
2190 bool *finished)
2191{
0c9bcc1d 2192 struct marvell_priv *priv = phydev->priv;
fc879f72
AL
2193 int ret;
2194
0c9bcc1d
AL
2195 if (priv->cable_test_tdr) {
2196 ret = marvell_vct5_amplitude_graph(phydev);
2197 *finished = true;
2198 return ret;
2199 }
2200
fc879f72
AL
2201 *finished = false;
2202
2203 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,
2204 MII_VCT7_CTRL);
2205
2206 if (ret < 0)
2207 return ret;
2208
2209 if (!(ret & MII_VCT7_CTRL_IN_PROGRESS)) {
2210 *finished = true;
2211
2212 return marvell_vct7_cable_test_report(phydev);
2213 }
2214
2215 return 0;
2216}
2217
0b04680f
AL
2218#ifdef CONFIG_HWMON
2219static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
2220{
975b388c 2221 int oldpage;
424ca4c5 2222 int ret = 0;
0b04680f
AL
2223 int val;
2224
2225 *temp = 0;
2226
424ca4c5
RK
2227 oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
2228 if (oldpage < 0)
2229 goto error;
975b388c 2230
0b04680f 2231 /* Enable temperature sensor */
424ca4c5 2232 ret = __phy_read(phydev, MII_88E1121_MISC_TEST);
0b04680f
AL
2233 if (ret < 0)
2234 goto error;
2235
424ca4c5
RK
2236 ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
2237 ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
0b04680f
AL
2238 if (ret < 0)
2239 goto error;
2240
2241 /* Wait for temperature to stabilize */
2242 usleep_range(10000, 12000);
2243
424ca4c5 2244 val = __phy_read(phydev, MII_88E1121_MISC_TEST);
0b04680f
AL
2245 if (val < 0) {
2246 ret = val;
2247 goto error;
2248 }
2249
2250 /* Disable temperature sensor */
424ca4c5
RK
2251 ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
2252 ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
0b04680f
AL
2253 if (ret < 0)
2254 goto error;
2255
2256 *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;
2257
2258error:
424ca4c5 2259 return phy_restore_page(phydev, oldpage, ret);
0b04680f
AL
2260}
2261
2262static int m88e1121_hwmon_read(struct device *dev,
2263 enum hwmon_sensor_types type,
2264 u32 attr, int channel, long *temp)
2265{
2266 struct phy_device *phydev = dev_get_drvdata(dev);
2267 int err;
2268
2269 switch (attr) {
2270 case hwmon_temp_input:
2271 err = m88e1121_get_temp(phydev, temp);
2272 break;
2273 default:
2274 return -EOPNOTSUPP;
2275 }
2276
2277 return err;
2278}
2279
2280static umode_t m88e1121_hwmon_is_visible(const void *data,
2281 enum hwmon_sensor_types type,
2282 u32 attr, int channel)
2283{
2284 if (type != hwmon_temp)
2285 return 0;
2286
2287 switch (attr) {
2288 case hwmon_temp_input:
2289 return 0444;
2290 default:
2291 return 0;
2292 }
2293}
2294
2295static u32 m88e1121_hwmon_chip_config[] = {
2296 HWMON_C_REGISTER_TZ,
2297 0
2298};
2299
2300static const struct hwmon_channel_info m88e1121_hwmon_chip = {
2301 .type = hwmon_chip,
2302 .config = m88e1121_hwmon_chip_config,
2303};
2304
2305static u32 m88e1121_hwmon_temp_config[] = {
2306 HWMON_T_INPUT,
2307 0
2308};
2309
2310static const struct hwmon_channel_info m88e1121_hwmon_temp = {
2311 .type = hwmon_temp,
2312 .config = m88e1121_hwmon_temp_config,
2313};
2314
2315static const struct hwmon_channel_info *m88e1121_hwmon_info[] = {
2316 &m88e1121_hwmon_chip,
2317 &m88e1121_hwmon_temp,
2318 NULL
2319};
2320
2321static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = {
2322 .is_visible = m88e1121_hwmon_is_visible,
2323 .read = m88e1121_hwmon_read,
2324};
2325
2326static const struct hwmon_chip_info m88e1121_hwmon_chip_info = {
2327 .ops = &m88e1121_hwmon_hwmon_ops,
2328 .info = m88e1121_hwmon_info,
2329};
2330
2331static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
2332{
2333 int ret;
2334
2335 *temp = 0;
2336
424ca4c5
RK
2337 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2338 MII_88E1510_TEMP_SENSOR);
0b04680f 2339 if (ret < 0)
424ca4c5 2340 return ret;
0b04680f
AL
2341
2342 *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;
2343
424ca4c5 2344 return 0;
0b04680f
AL
2345}
2346
f0a45816 2347static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
0b04680f
AL
2348{
2349 int ret;
2350
2351 *temp = 0;
2352
424ca4c5
RK
2353 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2354 MII_88E1121_MISC_TEST);
0b04680f 2355 if (ret < 0)
424ca4c5 2356 return ret;
0b04680f
AL
2357
2358 *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >>
2359 MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25;
2360 /* convert to mC */
2361 *temp *= 1000;
2362
424ca4c5 2363 return 0;
0b04680f
AL
2364}
2365
f0a45816 2366static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
0b04680f 2367{
0b04680f
AL
2368 temp = temp / 1000;
2369 temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
0b04680f 2370
424ca4c5
RK
2371 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2372 MII_88E1121_MISC_TEST,
2373 MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,
2374 temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);
0b04680f
AL
2375}
2376
f0a45816 2377static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
0b04680f
AL
2378{
2379 int ret;
2380
2381 *alarm = false;
2382
424ca4c5
RK
2383 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2384 MII_88E1121_MISC_TEST);
0b04680f 2385 if (ret < 0)
424ca4c5 2386 return ret;
0b04680f 2387
424ca4c5 2388 *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);
0b04680f 2389
424ca4c5 2390 return 0;
0b04680f
AL
2391}
2392
2393static int m88e1510_hwmon_read(struct device *dev,
2394 enum hwmon_sensor_types type,
2395 u32 attr, int channel, long *temp)
2396{
2397 struct phy_device *phydev = dev_get_drvdata(dev);
2398 int err;
2399
2400 switch (attr) {
2401 case hwmon_temp_input:
2402 err = m88e1510_get_temp(phydev, temp);
2403 break;
2404 case hwmon_temp_crit:
2405 err = m88e1510_get_temp_critical(phydev, temp);
2406 break;
2407 case hwmon_temp_max_alarm:
2408 err = m88e1510_get_temp_alarm(phydev, temp);
2409 break;
2410 default:
2411 return -EOPNOTSUPP;
2412 }
2413
2414 return err;
2415}
2416
2417static int m88e1510_hwmon_write(struct device *dev,
2418 enum hwmon_sensor_types type,
2419 u32 attr, int channel, long temp)
2420{
2421 struct phy_device *phydev = dev_get_drvdata(dev);
2422 int err;
2423
2424 switch (attr) {
2425 case hwmon_temp_crit:
2426 err = m88e1510_set_temp_critical(phydev, temp);
2427 break;
2428 default:
2429 return -EOPNOTSUPP;
2430 }
2431 return err;
2432}
2433
2434static umode_t m88e1510_hwmon_is_visible(const void *data,
2435 enum hwmon_sensor_types type,
2436 u32 attr, int channel)
2437{
2438 if (type != hwmon_temp)
2439 return 0;
2440
2441 switch (attr) {
2442 case hwmon_temp_input:
2443 case hwmon_temp_max_alarm:
2444 return 0444;
2445 case hwmon_temp_crit:
2446 return 0644;
2447 default:
2448 return 0;
2449 }
2450}
2451
2452static u32 m88e1510_hwmon_temp_config[] = {
2453 HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM,
2454 0
2455};
2456
2457static const struct hwmon_channel_info m88e1510_hwmon_temp = {
2458 .type = hwmon_temp,
2459 .config = m88e1510_hwmon_temp_config,
2460};
2461
2462static const struct hwmon_channel_info *m88e1510_hwmon_info[] = {
2463 &m88e1121_hwmon_chip,
2464 &m88e1510_hwmon_temp,
2465 NULL
2466};
2467
2468static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = {
2469 .is_visible = m88e1510_hwmon_is_visible,
2470 .read = m88e1510_hwmon_read,
2471 .write = m88e1510_hwmon_write,
2472};
2473
2474static const struct hwmon_chip_info m88e1510_hwmon_chip_info = {
2475 .ops = &m88e1510_hwmon_hwmon_ops,
2476 .info = m88e1510_hwmon_info,
2477};
2478
fee2d546
AL
2479static int m88e6390_get_temp(struct phy_device *phydev, long *temp)
2480{
2481 int sum = 0;
2482 int oldpage;
2483 int ret = 0;
2484 int i;
2485
2486 *temp = 0;
2487
2488 oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
2489 if (oldpage < 0)
2490 goto error;
2491
2492 /* Enable temperature sensor */
2493 ret = __phy_read(phydev, MII_88E6390_MISC_TEST);
2494 if (ret < 0)
2495 goto error;
2496
2497 ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK;
2498 ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE |
2499 MII_88E6390_MISC_TEST_SAMPLE_1S;
2500
2501 ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);
2502 if (ret < 0)
2503 goto error;
2504
2505 /* Wait for temperature to stabilize */
2506 usleep_range(10000, 12000);
2507
2508 /* Reading the temperature sense has an errata. You need to read
2509 * a number of times and take an average.
2510 */
2511 for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) {
2512 ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR);
2513 if (ret < 0)
2514 goto error;
2515 sum += ret & MII_88E6390_TEMP_SENSOR_MASK;
2516 }
2517
2518 sum /= MII_88E6390_TEMP_SENSOR_SAMPLES;
2519 *temp = (sum - 75) * 1000;
2520
2521 /* Disable temperature sensor */
2522 ret = __phy_read(phydev, MII_88E6390_MISC_TEST);
2523 if (ret < 0)
2524 goto error;
2525
2526 ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK;
2527 ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE;
2528
2529 ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);
2530
2531error:
2532 phy_restore_page(phydev, oldpage, ret);
2533
2534 return ret;
2535}
2536
2537static int m88e6390_hwmon_read(struct device *dev,
2538 enum hwmon_sensor_types type,
2539 u32 attr, int channel, long *temp)
2540{
2541 struct phy_device *phydev = dev_get_drvdata(dev);
2542 int err;
2543
2544 switch (attr) {
2545 case hwmon_temp_input:
2546 err = m88e6390_get_temp(phydev, temp);
2547 break;
2548 default:
2549 return -EOPNOTSUPP;
2550 }
2551
2552 return err;
2553}
2554
2555static umode_t m88e6390_hwmon_is_visible(const void *data,
2556 enum hwmon_sensor_types type,
2557 u32 attr, int channel)
2558{
2559 if (type != hwmon_temp)
2560 return 0;
2561
2562 switch (attr) {
2563 case hwmon_temp_input:
2564 return 0444;
2565 default:
2566 return 0;
2567 }
2568}
2569
2570static u32 m88e6390_hwmon_temp_config[] = {
2571 HWMON_T_INPUT,
2572 0
2573};
2574
2575static const struct hwmon_channel_info m88e6390_hwmon_temp = {
2576 .type = hwmon_temp,
2577 .config = m88e6390_hwmon_temp_config,
2578};
2579
2580static const struct hwmon_channel_info *m88e6390_hwmon_info[] = {
2581 &m88e1121_hwmon_chip,
2582 &m88e6390_hwmon_temp,
2583 NULL
2584};
2585
2586static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = {
2587 .is_visible = m88e6390_hwmon_is_visible,
2588 .read = m88e6390_hwmon_read,
2589};
2590
2591static const struct hwmon_chip_info m88e6390_hwmon_chip_info = {
2592 .ops = &m88e6390_hwmon_hwmon_ops,
2593 .info = m88e6390_hwmon_info,
2594};
2595
0b04680f
AL
2596static int marvell_hwmon_name(struct phy_device *phydev)
2597{
2598 struct marvell_priv *priv = phydev->priv;
2599 struct device *dev = &phydev->mdio.dev;
2600 const char *devname = dev_name(dev);
2601 size_t len = strlen(devname);
2602 int i, j;
2603
2604 priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL);
2605 if (!priv->hwmon_name)
2606 return -ENOMEM;
2607
2608 for (i = j = 0; i < len && devname[i]; i++) {
2609 if (isalnum(devname[i]))
2610 priv->hwmon_name[j++] = devname[i];
2611 }
2612
2613 return 0;
2614}
2615
2616static int marvell_hwmon_probe(struct phy_device *phydev,
2617 const struct hwmon_chip_info *chip)
2618{
2619 struct marvell_priv *priv = phydev->priv;
2620 struct device *dev = &phydev->mdio.dev;
2621 int err;
2622
2623 err = marvell_hwmon_name(phydev);
2624 if (err)
2625 return err;
2626
2627 priv->hwmon_dev = devm_hwmon_device_register_with_info(
2628 dev, priv->hwmon_name, phydev, chip, NULL);
2629
2630 return PTR_ERR_OR_ZERO(priv->hwmon_dev);
2631}
2632
2633static int m88e1121_hwmon_probe(struct phy_device *phydev)
2634{
2635 return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info);
2636}
2637
2638static int m88e1510_hwmon_probe(struct phy_device *phydev)
2639{
2640 return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info);
2641}
fee2d546
AL
2642
2643static int m88e6390_hwmon_probe(struct phy_device *phydev)
2644{
2645 return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info);
2646}
0b04680f
AL
2647#else
2648static int m88e1121_hwmon_probe(struct phy_device *phydev)
2649{
2650 return 0;
2651}
2652
2653static int m88e1510_hwmon_probe(struct phy_device *phydev)
2654{
2655 return 0;
2656}
fee2d546
AL
2657
2658static int m88e6390_hwmon_probe(struct phy_device *phydev)
2659{
2660 return 0;
2661}
0b04680f
AL
2662#endif
2663
d2fa47d9
AL
2664static int marvell_probe(struct phy_device *phydev)
2665{
2666 struct marvell_priv *priv;
2667
e5a03bfd 2668 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
d2fa47d9
AL
2669 if (!priv)
2670 return -ENOMEM;
2671
2672 phydev->priv = priv;
2673
2674 return 0;
2675}
2676
0b04680f
AL
2677static int m88e1121_probe(struct phy_device *phydev)
2678{
2679 int err;
2680
2681 err = marvell_probe(phydev);
2682 if (err)
2683 return err;
2684
2685 return m88e1121_hwmon_probe(phydev);
2686}
2687
2688static int m88e1510_probe(struct phy_device *phydev)
2689{
2690 int err;
2691
2692 err = marvell_probe(phydev);
2693 if (err)
2694 return err;
2695
2696 return m88e1510_hwmon_probe(phydev);
2697}
2698
fee2d546
AL
2699static int m88e6390_probe(struct phy_device *phydev)
2700{
2701 int err;
2702
2703 err = marvell_probe(phydev);
2704 if (err)
2705 return err;
2706
2707 return m88e6390_hwmon_probe(phydev);
2708}
2709
e5479239
OJ
2710static struct phy_driver marvell_drivers[] = {
2711 {
2f495c39
BH
2712 .phy_id = MARVELL_PHY_ID_88E1101,
2713 .phy_id_mask = MARVELL_PHY_ID_MASK,
e5479239 2714 .name = "Marvell 88E1101",
dcdecdcf 2715 /* PHY_GBIT_FEATURES */
18702414 2716 .probe = marvell_probe,
ef0f9545
MK
2717 .config_init = marvell_config_init,
2718 .config_aneg = m88e1101_config_aneg,
ef0f9545 2719 .config_intr = marvell_config_intr,
a0723b37 2720 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2721 .resume = genphy_resume,
2722 .suspend = genphy_suspend,
424ca4c5
RK
2723 .read_page = marvell_read_page,
2724 .write_page = marvell_write_page,
d2fa47d9
AL
2725 .get_sset_count = marvell_get_sset_count,
2726 .get_strings = marvell_get_strings,
2727 .get_stats = marvell_get_stats,
e5479239 2728 },
85cfb534 2729 {
2f495c39
BH
2730 .phy_id = MARVELL_PHY_ID_88E1112,
2731 .phy_id_mask = MARVELL_PHY_ID_MASK,
85cfb534 2732 .name = "Marvell 88E1112",
dcdecdcf 2733 /* PHY_GBIT_FEATURES */
d2fa47d9 2734 .probe = marvell_probe,
ef0f9545
MK
2735 .config_init = m88e1111_config_init,
2736 .config_aneg = marvell_config_aneg,
ef0f9545 2737 .config_intr = marvell_config_intr,
a0723b37 2738 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2739 .resume = genphy_resume,
2740 .suspend = genphy_suspend,
424ca4c5
RK
2741 .read_page = marvell_read_page,
2742 .write_page = marvell_write_page,
d2fa47d9
AL
2743 .get_sset_count = marvell_get_sset_count,
2744 .get_strings = marvell_get_strings,
2745 .get_stats = marvell_get_stats,
262caf47
HK
2746 .get_tunable = m88e1011_get_tunable,
2747 .set_tunable = m88e1011_set_tunable,
85cfb534 2748 },
e5479239 2749 {
2f495c39
BH
2750 .phy_id = MARVELL_PHY_ID_88E1111,
2751 .phy_id_mask = MARVELL_PHY_ID_MASK,
e5479239 2752 .name = "Marvell 88E1111",
dcdecdcf 2753 /* PHY_GBIT_FEATURES */
d2fa47d9 2754 .probe = marvell_probe,
ef0f9545 2755 .config_init = m88e1111_config_init,
1887023a
RH
2756 .config_aneg = m88e1111_config_aneg,
2757 .read_status = marvell_read_status,
1887023a 2758 .config_intr = marvell_config_intr,
a0723b37 2759 .handle_interrupt = marvell_handle_interrupt,
1887023a
RH
2760 .resume = genphy_resume,
2761 .suspend = genphy_suspend,
2762 .read_page = marvell_read_page,
2763 .write_page = marvell_write_page,
2764 .get_sset_count = marvell_get_sset_count,
2765 .get_strings = marvell_get_strings,
2766 .get_stats = marvell_get_stats,
2767 .get_tunable = m88e1111_get_tunable,
2768 .set_tunable = m88e1111_set_tunable,
2769 },
2770 {
2771 .phy_id = MARVELL_PHY_ID_88E1111_FINISAR,
2772 .phy_id_mask = MARVELL_PHY_ID_MASK,
2773 .name = "Marvell 88E1111 (Finisar)",
2774 /* PHY_GBIT_FEATURES */
2775 .probe = marvell_probe,
2776 .config_init = m88e1111_config_init,
2777 .config_aneg = m88e1111_config_aneg,
ef0f9545 2778 .read_status = marvell_read_status,
ef0f9545 2779 .config_intr = marvell_config_intr,
a0723b37 2780 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2781 .resume = genphy_resume,
2782 .suspend = genphy_suspend,
424ca4c5
RK
2783 .read_page = marvell_read_page,
2784 .write_page = marvell_write_page,
d2fa47d9
AL
2785 .get_sset_count = marvell_get_sset_count,
2786 .get_strings = marvell_get_strings,
2787 .get_stats = marvell_get_stats,
5c6bc519
HK
2788 .get_tunable = m88e1111_get_tunable,
2789 .set_tunable = m88e1111_set_tunable,
e5479239 2790 },
605f196e 2791 {
2f495c39
BH
2792 .phy_id = MARVELL_PHY_ID_88E1118,
2793 .phy_id_mask = MARVELL_PHY_ID_MASK,
605f196e 2794 .name = "Marvell 88E1118",
dcdecdcf 2795 /* PHY_GBIT_FEATURES */
d2fa47d9 2796 .probe = marvell_probe,
ef0f9545
MK
2797 .config_init = m88e1118_config_init,
2798 .config_aneg = m88e1118_config_aneg,
ef0f9545 2799 .config_intr = marvell_config_intr,
a0723b37 2800 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2801 .resume = genphy_resume,
2802 .suspend = genphy_suspend,
424ca4c5
RK
2803 .read_page = marvell_read_page,
2804 .write_page = marvell_write_page,
d2fa47d9
AL
2805 .get_sset_count = marvell_get_sset_count,
2806 .get_strings = marvell_get_strings,
2807 .get_stats = marvell_get_stats,
605f196e 2808 },
140bc929 2809 {
2f495c39
BH
2810 .phy_id = MARVELL_PHY_ID_88E1121R,
2811 .phy_id_mask = MARVELL_PHY_ID_MASK,
140bc929 2812 .name = "Marvell 88E1121R",
dcdecdcf 2813 /* PHY_GBIT_FEATURES */
ef0f9545
MK
2814 .probe = m88e1121_probe,
2815 .config_init = marvell_config_init,
2816 .config_aneg = m88e1121_config_aneg,
2817 .read_status = marvell_read_status,
ef0f9545 2818 .config_intr = marvell_config_intr,
a0723b37 2819 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2820 .resume = genphy_resume,
2821 .suspend = genphy_suspend,
424ca4c5
RK
2822 .read_page = marvell_read_page,
2823 .write_page = marvell_write_page,
d2fa47d9
AL
2824 .get_sset_count = marvell_get_sset_count,
2825 .get_strings = marvell_get_strings,
2826 .get_stats = marvell_get_stats,
911af5e1
HK
2827 .get_tunable = m88e1011_get_tunable,
2828 .set_tunable = m88e1011_set_tunable,
140bc929 2829 },
3ff1c259 2830 {
337ac9d5 2831 .phy_id = MARVELL_PHY_ID_88E1318S,
6ba74014 2832 .phy_id_mask = MARVELL_PHY_ID_MASK,
337ac9d5 2833 .name = "Marvell 88E1318S",
dcdecdcf 2834 /* PHY_GBIT_FEATURES */
d2fa47d9 2835 .probe = marvell_probe,
ef0f9545
MK
2836 .config_init = m88e1318_config_init,
2837 .config_aneg = m88e1318_config_aneg,
2838 .read_status = marvell_read_status,
ef0f9545 2839 .config_intr = marvell_config_intr,
a0723b37 2840 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2841 .get_wol = m88e1318_get_wol,
2842 .set_wol = m88e1318_set_wol,
2843 .resume = genphy_resume,
2844 .suspend = genphy_suspend,
424ca4c5
RK
2845 .read_page = marvell_read_page,
2846 .write_page = marvell_write_page,
d2fa47d9
AL
2847 .get_sset_count = marvell_get_sset_count,
2848 .get_strings = marvell_get_strings,
2849 .get_stats = marvell_get_stats,
3ff1c259 2850 },
e5479239 2851 {
2f495c39
BH
2852 .phy_id = MARVELL_PHY_ID_88E1145,
2853 .phy_id_mask = MARVELL_PHY_ID_MASK,
e5479239 2854 .name = "Marvell 88E1145",
dcdecdcf 2855 /* PHY_GBIT_FEATURES */
d2fa47d9 2856 .probe = marvell_probe,
ef0f9545
MK
2857 .config_init = m88e1145_config_init,
2858 .config_aneg = m88e1101_config_aneg,
ef0f9545 2859 .config_intr = marvell_config_intr,
a0723b37 2860 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2861 .resume = genphy_resume,
2862 .suspend = genphy_suspend,
424ca4c5
RK
2863 .read_page = marvell_read_page,
2864 .write_page = marvell_write_page,
d2fa47d9
AL
2865 .get_sset_count = marvell_get_sset_count,
2866 .get_strings = marvell_get_strings,
2867 .get_stats = marvell_get_stats,
a319fb52
HK
2868 .get_tunable = m88e1111_get_tunable,
2869 .set_tunable = m88e1111_set_tunable,
ac8c635a 2870 },
90600732
DD
2871 {
2872 .phy_id = MARVELL_PHY_ID_88E1149R,
2873 .phy_id_mask = MARVELL_PHY_ID_MASK,
2874 .name = "Marvell 88E1149R",
dcdecdcf 2875 /* PHY_GBIT_FEATURES */
d2fa47d9 2876 .probe = marvell_probe,
ef0f9545
MK
2877 .config_init = m88e1149_config_init,
2878 .config_aneg = m88e1118_config_aneg,
ef0f9545 2879 .config_intr = marvell_config_intr,
a0723b37 2880 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2881 .resume = genphy_resume,
2882 .suspend = genphy_suspend,
424ca4c5
RK
2883 .read_page = marvell_read_page,
2884 .write_page = marvell_write_page,
d2fa47d9
AL
2885 .get_sset_count = marvell_get_sset_count,
2886 .get_strings = marvell_get_strings,
2887 .get_stats = marvell_get_stats,
90600732 2888 },
ac8c635a 2889 {
2f495c39
BH
2890 .phy_id = MARVELL_PHY_ID_88E1240,
2891 .phy_id_mask = MARVELL_PHY_ID_MASK,
ac8c635a 2892 .name = "Marvell 88E1240",
dcdecdcf 2893 /* PHY_GBIT_FEATURES */
d2fa47d9 2894 .probe = marvell_probe,
ef0f9545
MK
2895 .config_init = m88e1111_config_init,
2896 .config_aneg = marvell_config_aneg,
ef0f9545 2897 .config_intr = marvell_config_intr,
a0723b37 2898 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2899 .resume = genphy_resume,
2900 .suspend = genphy_suspend,
424ca4c5
RK
2901 .read_page = marvell_read_page,
2902 .write_page = marvell_write_page,
d2fa47d9
AL
2903 .get_sset_count = marvell_get_sset_count,
2904 .get_strings = marvell_get_strings,
2905 .get_stats = marvell_get_stats,
ac8c635a 2906 },
3da09a51
MS
2907 {
2908 .phy_id = MARVELL_PHY_ID_88E1116R,
2909 .phy_id_mask = MARVELL_PHY_ID_MASK,
2910 .name = "Marvell 88E1116R",
dcdecdcf 2911 /* PHY_GBIT_FEATURES */
d2fa47d9 2912 .probe = marvell_probe,
ef0f9545 2913 .config_init = m88e1116r_config_init,
ef0f9545 2914 .config_intr = marvell_config_intr,
a0723b37 2915 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2916 .resume = genphy_resume,
2917 .suspend = genphy_suspend,
424ca4c5
RK
2918 .read_page = marvell_read_page,
2919 .write_page = marvell_write_page,
d2fa47d9
AL
2920 .get_sset_count = marvell_get_sset_count,
2921 .get_strings = marvell_get_strings,
2922 .get_stats = marvell_get_stats,
262caf47
HK
2923 .get_tunable = m88e1011_get_tunable,
2924 .set_tunable = m88e1011_set_tunable,
3da09a51 2925 },
10e24caa
MS
2926 {
2927 .phy_id = MARVELL_PHY_ID_88E1510,
2928 .phy_id_mask = MARVELL_PHY_ID_MASK,
2929 .name = "Marvell 88E1510",
719655a1 2930 .features = PHY_GBIT_FIBRE_FEATURES,
fc879f72 2931 .flags = PHY_POLL_CABLE_TEST,
ef0f9545
MK
2932 .probe = m88e1510_probe,
2933 .config_init = m88e1510_config_init,
2934 .config_aneg = m88e1510_config_aneg,
2935 .read_status = marvell_read_status,
ef0f9545 2936 .config_intr = marvell_config_intr,
a0723b37 2937 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2938 .get_wol = m88e1318_get_wol,
2939 .set_wol = m88e1318_set_wol,
2940 .resume = marvell_resume,
2941 .suspend = marvell_suspend,
424ca4c5
RK
2942 .read_page = marvell_read_page,
2943 .write_page = marvell_write_page,
d2fa47d9
AL
2944 .get_sset_count = marvell_get_sset_count,
2945 .get_strings = marvell_get_strings,
2946 .get_stats = marvell_get_stats,
f0f9b4ed 2947 .set_loopback = genphy_loopback,
262caf47
HK
2948 .get_tunable = m88e1011_get_tunable,
2949 .set_tunable = m88e1011_set_tunable,
fc879f72 2950 .cable_test_start = marvell_vct7_cable_test_start,
0c9bcc1d 2951 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
fc879f72 2952 .cable_test_get_status = marvell_vct7_cable_test_get_status,
10e24caa 2953 },
819ec8e1
AL
2954 {
2955 .phy_id = MARVELL_PHY_ID_88E1540,
2956 .phy_id_mask = MARVELL_PHY_ID_MASK,
2957 .name = "Marvell 88E1540",
dcdecdcf 2958 /* PHY_GBIT_FEATURES */
fc879f72 2959 .flags = PHY_POLL_CABLE_TEST,
18702414 2960 .probe = m88e1510_probe,
ef0f9545
MK
2961 .config_init = marvell_config_init,
2962 .config_aneg = m88e1510_config_aneg,
2963 .read_status = marvell_read_status,
ef0f9545 2964 .config_intr = marvell_config_intr,
a0723b37 2965 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2966 .resume = genphy_resume,
2967 .suspend = genphy_suspend,
424ca4c5
RK
2968 .read_page = marvell_read_page,
2969 .write_page = marvell_write_page,
d2fa47d9
AL
2970 .get_sset_count = marvell_get_sset_count,
2971 .get_strings = marvell_get_strings,
2972 .get_stats = marvell_get_stats,
69f42be8
HK
2973 .get_tunable = m88e1540_get_tunable,
2974 .set_tunable = m88e1540_set_tunable,
fc879f72 2975 .cable_test_start = marvell_vct7_cable_test_start,
0c9bcc1d 2976 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
fc879f72 2977 .cable_test_get_status = marvell_vct7_cable_test_get_status,
819ec8e1 2978 },
60f06fde
AL
2979 {
2980 .phy_id = MARVELL_PHY_ID_88E1545,
2981 .phy_id_mask = MARVELL_PHY_ID_MASK,
2982 .name = "Marvell 88E1545",
2983 .probe = m88e1510_probe,
dcdecdcf 2984 /* PHY_GBIT_FEATURES */
fc879f72 2985 .flags = PHY_POLL_CABLE_TEST,
ef0f9545
MK
2986 .config_init = marvell_config_init,
2987 .config_aneg = m88e1510_config_aneg,
2988 .read_status = marvell_read_status,
ef0f9545 2989 .config_intr = marvell_config_intr,
a0723b37 2990 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
2991 .resume = genphy_resume,
2992 .suspend = genphy_suspend,
424ca4c5
RK
2993 .read_page = marvell_read_page,
2994 .write_page = marvell_write_page,
60f06fde
AL
2995 .get_sset_count = marvell_get_sset_count,
2996 .get_strings = marvell_get_strings,
2997 .get_stats = marvell_get_stats,
262caf47
HK
2998 .get_tunable = m88e1540_get_tunable,
2999 .set_tunable = m88e1540_set_tunable,
fc879f72 3000 .cable_test_start = marvell_vct7_cable_test_start,
0c9bcc1d 3001 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
fc879f72 3002 .cable_test_get_status = marvell_vct7_cable_test_get_status,
60f06fde 3003 },
6b358aed
SH
3004 {
3005 .phy_id = MARVELL_PHY_ID_88E3016,
3006 .phy_id_mask = MARVELL_PHY_ID_MASK,
3007 .name = "Marvell 88E3016",
dcdecdcf 3008 /* PHY_BASIC_FEATURES */
d2fa47d9 3009 .probe = marvell_probe,
ef0f9545
MK
3010 .config_init = m88e3016_config_init,
3011 .aneg_done = marvell_aneg_done,
3012 .read_status = marvell_read_status,
ef0f9545 3013 .config_intr = marvell_config_intr,
a0723b37 3014 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
3015 .resume = genphy_resume,
3016 .suspend = genphy_suspend,
424ca4c5
RK
3017 .read_page = marvell_read_page,
3018 .write_page = marvell_write_page,
d2fa47d9
AL
3019 .get_sset_count = marvell_get_sset_count,
3020 .get_strings = marvell_get_strings,
3021 .get_stats = marvell_get_stats,
6b358aed 3022 },
e4cf8a38
AL
3023 {
3024 .phy_id = MARVELL_PHY_ID_88E6390,
3025 .phy_id_mask = MARVELL_PHY_ID_MASK,
3026 .name = "Marvell 88E6390",
dcdecdcf 3027 /* PHY_GBIT_FEATURES */
fc879f72 3028 .flags = PHY_POLL_CABLE_TEST,
fee2d546 3029 .probe = m88e6390_probe,
ef0f9545
MK
3030 .config_init = marvell_config_init,
3031 .config_aneg = m88e6390_config_aneg,
3032 .read_status = marvell_read_status,
ef0f9545 3033 .config_intr = marvell_config_intr,
a0723b37 3034 .handle_interrupt = marvell_handle_interrupt,
ef0f9545
MK
3035 .resume = genphy_resume,
3036 .suspend = genphy_suspend,
424ca4c5
RK
3037 .read_page = marvell_read_page,
3038 .write_page = marvell_write_page,
e4cf8a38
AL
3039 .get_sset_count = marvell_get_sset_count,
3040 .get_strings = marvell_get_strings,
3041 .get_stats = marvell_get_stats,
69f42be8
HK
3042 .get_tunable = m88e1540_get_tunable,
3043 .set_tunable = m88e1540_set_tunable,
fc879f72 3044 .cable_test_start = marvell_vct7_cable_test_start,
0c9bcc1d 3045 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
fc879f72 3046 .cable_test_get_status = marvell_vct7_cable_test_get_status,
e4cf8a38 3047 },
a602ea86
MK
3048 {
3049 .phy_id = MARVELL_PHY_ID_88E1340S,
3050 .phy_id_mask = MARVELL_PHY_ID_MASK,
3051 .name = "Marvell 88E1340S",
3052 .probe = m88e1510_probe,
3053 /* PHY_GBIT_FEATURES */
3054 .config_init = marvell_config_init,
3055 .config_aneg = m88e1510_config_aneg,
3056 .read_status = marvell_read_status,
a602ea86 3057 .config_intr = marvell_config_intr,
a0723b37 3058 .handle_interrupt = marvell_handle_interrupt,
a602ea86
MK
3059 .resume = genphy_resume,
3060 .suspend = genphy_suspend,
3061 .read_page = marvell_read_page,
3062 .write_page = marvell_write_page,
3063 .get_sset_count = marvell_get_sset_count,
3064 .get_strings = marvell_get_strings,
3065 .get_stats = marvell_get_stats,
3066 .get_tunable = m88e1540_get_tunable,
3067 .set_tunable = m88e1540_set_tunable,
3068 },
f59babf9
MK
3069 {
3070 .phy_id = MARVELL_PHY_ID_88E1548P,
3071 .phy_id_mask = MARVELL_PHY_ID_MASK,
3072 .name = "Marvell 88E1548P",
3073 .probe = m88e1510_probe,
3074 .features = PHY_GBIT_FIBRE_FEATURES,
3075 .config_init = marvell_config_init,
3076 .config_aneg = m88e1510_config_aneg,
3077 .read_status = marvell_read_status,
f59babf9 3078 .config_intr = marvell_config_intr,
a0723b37 3079 .handle_interrupt = marvell_handle_interrupt,
f59babf9
MK
3080 .resume = genphy_resume,
3081 .suspend = genphy_suspend,
3082 .read_page = marvell_read_page,
3083 .write_page = marvell_write_page,
3084 .get_sset_count = marvell_get_sset_count,
3085 .get_strings = marvell_get_strings,
3086 .get_stats = marvell_get_stats,
3087 .get_tunable = m88e1540_get_tunable,
3088 .set_tunable = m88e1540_set_tunable,
3089 },
00db8189
AF
3090};
3091
50fd7150 3092module_phy_driver(marvell_drivers);
4e4f10f6 3093
cf93c945 3094static struct mdio_device_id __maybe_unused marvell_tbl[] = {
f5e1cabf
MS
3095 { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
3096 { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
3097 { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
1887023a 3098 { MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK },
f5e1cabf
MS
3099 { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
3100 { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
3101 { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
3102 { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
3103 { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
3104 { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
3da09a51 3105 { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
10e24caa 3106 { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
819ec8e1 3107 { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
60f06fde 3108 { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },
6b358aed 3109 { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
e4cf8a38 3110 { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK },
a602ea86 3111 { MARVELL_PHY_ID_88E1340S, MARVELL_PHY_ID_MASK },
f59babf9 3112 { MARVELL_PHY_ID_88E1548P, MARVELL_PHY_ID_MASK },
4e4f10f6
DW
3113 { }
3114};
3115
3116MODULE_DEVICE_TABLE(mdio, marvell_tbl);