blob: 2429db614b59ab4dfc91b4053edfebbff6effb8a [file] [log] [blame]
Andrew Lunna2443fd2019-01-21 19:05:50 +01001// SPDX-License-Identifier: GPL-2.0+
Andy Fleming00db8182005-07-30 19:31:23 -04002/*
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 *
Michael Stapelberg3871c382013-03-11 13:56:45 +000011 * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>
Andy Fleming00db8182005-07-30 19:31:23 -040012 */
Andy Fleming00db8182005-07-30 19:31:23 -040013#include <linux/kernel.h>
Andy Fleming00db8182005-07-30 19:31:23 -040014#include <linux/string.h>
Andrew Lunn0b046802017-01-20 01:37:49 +010015#include <linux/ctype.h>
Andy Fleming00db8182005-07-30 19:31:23 -040016#include <linux/errno.h>
17#include <linux/unistd.h>
Andrew Lunn0b046802017-01-20 01:37:49 +010018#include <linux/hwmon.h>
Andy Fleming00db8182005-07-30 19:31:23 -040019#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>
Andy Fleming00db8182005-07-30 19:31:23 -040028#include <linux/mii.h>
29#include <linux/ethtool.h>
Andrew Lunnfc879f72020-05-10 21:12:38 +020030#include <linux/ethtool_netlink.h>
Andy Fleming00db8182005-07-30 19:31:23 -040031#include <linux/phy.h>
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +100032#include <linux/marvell_phy.h>
Heiner Kallweit69f42be2019-03-25 19:35:41 +010033#include <linux/bitfield.h>
David Daneycf41a512010-11-19 12:13:18 +000034#include <linux/of.h>
Ivan Bornyakovb697d9d2021-08-12 16:42:56 +030035#include <linux/sfp.h>
Andy Fleming00db8182005-07-30 19:31:23 -040036
Avinash Kumareea3b202013-09-30 09:36:44 +053037#include <linux/io.h>
Andy Fleming00db8182005-07-30 19:31:23 -040038#include <asm/irq.h>
Avinash Kumareea3b202013-09-30 09:36:44 +053039#include <linux/uaccess.h>
Andy Fleming00db8182005-07-30 19:31:23 -040040
David Daney27d916d2010-11-19 11:58:52 +000041#define MII_MARVELL_PHY_PAGE 22
Andrew Lunn52295662017-05-25 21:42:08 +020042#define MII_MARVELL_COPPER_PAGE 0x00
43#define MII_MARVELL_FIBER_PAGE 0x01
44#define MII_MARVELL_MSCR_PAGE 0x02
45#define MII_MARVELL_LED_PAGE 0x03
Andrew Lunn0c9bcc12020-05-27 00:21:40 +020046#define MII_MARVELL_VCT5_PAGE 0x05
Andrew Lunn52295662017-05-25 21:42:08 +020047#define MII_MARVELL_MISC_TEST_PAGE 0x06
Andrew Lunnfc879f72020-05-10 21:12:38 +020048#define MII_MARVELL_VCT7_PAGE 0x07
Andrew Lunn52295662017-05-25 21:42:08 +020049#define MII_MARVELL_WOL_PAGE 0x11
Ivan Bornyakovb697d9d2021-08-12 16:42:56 +030050#define MII_MARVELL_MODE_PAGE 0x12
David Daney27d916d2010-11-19 11:58:52 +000051
Andy Fleming00db8182005-07-30 19:31:23 -040052#define MII_M1011_IEVENT 0x13
53#define MII_M1011_IEVENT_CLEAR 0x0000
54
55#define MII_M1011_IMASK 0x12
56#define MII_M1011_IMASK_INIT 0x6400
57#define MII_M1011_IMASK_CLEAR 0x0000
58
Andrew Lunnfecd5e92017-07-30 22:41:49 +020059#define MII_M1011_PHY_SCR 0x10
60#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)
Heiner Kallweitf8d975b2019-10-28 20:52:22 +010061#define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12)
Heiner Kallweita3bdfce2019-10-19 15:57:33 +020062#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8
Andrew Lunnfecd5e92017-07-30 22:41:49 +020063#define MII_M1011_PHY_SCR_MDI (0x0 << 5)
64#define MII_M1011_PHY_SCR_MDI_X (0x1 << 5)
65#define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5)
Andy Fleming76884672007-02-09 18:13:58 -060066
Heiner Kallweita3bdfce2019-10-19 15:57:33 +020067#define MII_M1011_PHY_SSR 0x11
68#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5)
69
Andy Fleming76884672007-02-09 18:13:58 -060070#define MII_M1111_PHY_LED_CONTROL 0x18
71#define MII_M1111_PHY_LED_DIRECT 0x4100
72#define MII_M1111_PHY_LED_COMBINE 0x411c
Kim Phillips895ee682007-06-05 18:46:47 +080073#define MII_M1111_PHY_EXT_CR 0x14
Heiner Kallweit5c6bc512019-10-28 20:53:25 +010074#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9)
75#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 8
76#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8)
Andrew Lunn61111592017-07-30 22:41:46 +020077#define MII_M1111_RGMII_RX_DELAY BIT(7)
78#define MII_M1111_RGMII_TX_DELAY BIT(1)
Kim Phillips895ee682007-06-05 18:46:47 +080079#define MII_M1111_PHY_EXT_SR 0x1b
Alexandr Smirnovbe937f12008-03-19 00:37:24 +030080
81#define MII_M1111_HWCFG_MODE_MASK 0xf
Alexandr Smirnovbe937f12008-03-19 00:37:24 +030082#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3
Kapil Juneja4117b5b2007-05-11 18:25:18 -050083#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4
Andrew Lunn865b813a2017-07-30 22:41:47 +020084#define MII_M1111_HWCFG_MODE_RTBI 0x7
Robert Hancock18870232020-10-28 11:15:40 -060085#define MII_M1111_HWCFG_MODE_COPPER_1000X_AN 0x8
Liu Yu-B132015f8cbc12010-01-13 22:13:19 +000086#define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9
Andrew Lunn865b813a2017-07-30 22:41:47 +020087#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb
Robert Hancock18870232020-10-28 11:15:40 -060088#define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN 0xc
89#define MII_M1111_HWCFG_SERIAL_AN_BYPASS BIT(12)
Andrew Lunn865b813a2017-07-30 22:41:47 +020090#define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13)
91#define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15)
Alexandr Smirnovbe937f12008-03-19 00:37:24 +030092
Cyril Chemparathyc477d042010-08-02 09:44:53 +000093#define MII_88E1121_PHY_MSCR_REG 21
94#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5)
95#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
Russell King424ca4c2018-01-02 10:58:48 +000096#define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4))
Cyril Chemparathyc477d042010-08-02 09:44:53 +000097
Andrew Lunn0b046802017-01-20 01:37:49 +010098#define MII_88E1121_MISC_TEST 0x1a
99#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00
100#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8
101#define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7)
102#define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6)
103#define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5)
104#define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f
105
106#define MII_88E1510_TEMP_SENSOR 0x1b
107#define MII_88E1510_TEMP_SENSOR_MASK 0xff
108
Heiner Kallweit69f42be2019-03-25 19:35:41 +0100109#define MII_88E1540_COPPER_CTRL3 0x1a
110#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10)
111#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0
112#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1
113#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2
114#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3
115#define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9)
116
Andrew Lunnfee2d542018-01-09 22:42:09 +0100117#define MII_88E6390_MISC_TEST 0x1b
Marek Behún4f920c292021-04-20 09:54:00 +0200118#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S (0x0 << 14)
119#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE (0x1 << 14)
120#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_ONESHOT (0x2 << 14)
121#define MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE (0x3 << 14)
122#define MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK (0x3 << 14)
Marek Behúna978f7c2021-04-20 09:54:03 +0200123#define MII_88E6393_MISC_TEST_SAMPLES_2048 (0x0 << 11)
124#define MII_88E6393_MISC_TEST_SAMPLES_4096 (0x1 << 11)
125#define MII_88E6393_MISC_TEST_SAMPLES_8192 (0x2 << 11)
126#define MII_88E6393_MISC_TEST_SAMPLES_16384 (0x3 << 11)
127#define MII_88E6393_MISC_TEST_SAMPLES_MASK (0x3 << 11)
128#define MII_88E6393_MISC_TEST_RATE_2_3MS (0x5 << 8)
129#define MII_88E6393_MISC_TEST_RATE_6_4MS (0x6 << 8)
130#define MII_88E6393_MISC_TEST_RATE_11_9MS (0x7 << 8)
131#define MII_88E6393_MISC_TEST_RATE_MASK (0x7 << 8)
Andrew Lunnfee2d542018-01-09 22:42:09 +0100132
133#define MII_88E6390_TEMP_SENSOR 0x1c
Marek Behúna978f7c2021-04-20 09:54:03 +0200134#define MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK 0xff00
135#define MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT 8
136#define MII_88E6390_TEMP_SENSOR_MASK 0xff
137#define MII_88E6390_TEMP_SENSOR_SAMPLES 10
Andrew Lunnfee2d542018-01-09 22:42:09 +0100138
Cyril Chemparathy337ac9d2010-10-29 13:50:25 -0700139#define MII_88E1318S_PHY_MSCR1_REG 16
140#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
Cyril Chemparathy3ff1c252010-08-03 19:36:06 -0700141
Michael Stapelberg3871c382013-03-11 13:56:45 +0000142/* Copper Specific Interrupt Enable Register */
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200143#define MII_88E1318S_PHY_CSIER 0x12
Michael Stapelberg3871c382013-03-11 13:56:45 +0000144/* WOL Event Interrupt Enable */
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200145#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
Michael Stapelberg3871c382013-03-11 13:56:45 +0000146
147/* LED Timer Control Register */
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200148#define MII_88E1318S_PHY_LED_TCR 0x12
149#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
150#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
151#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)
Michael Stapelberg3871c382013-03-11 13:56:45 +0000152
153/* Magic Packet MAC address registers */
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200154#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17
155#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18
156#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19
Michael Stapelberg3871c382013-03-11 13:56:45 +0000157
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200158#define MII_88E1318S_PHY_WOL_CTRL 0x10
159#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12)
Song Yoong Siang61646592021-08-13 16:45:08 +0800160#define MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE BIT(13)
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200161#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
Michael Stapelberg3871c382013-03-11 13:56:45 +0000162
Wang Dongsheng07777242018-07-01 23:15:46 -0700163#define MII_PHY_LED_CTRL 16
Sergei Poselenov140bc922009-04-07 02:01:41 +0000164#define MII_88E1121_PHY_LED_DEF 0x0030
Wang Dongsheng07777242018-07-01 23:15:46 -0700165#define MII_88E1510_PHY_LED_DEF 0x1177
Jian Shena93f7fe2019-04-22 21:52:23 +0800166#define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040
Sergei Poselenov140bc922009-04-07 02:01:41 +0000167
Alexandr Smirnovbe937f12008-03-19 00:37:24 +0300168#define MII_M1011_PHY_STATUS 0x11
169#define MII_M1011_PHY_STATUS_1000 0x8000
170#define MII_M1011_PHY_STATUS_100 0x4000
171#define MII_M1011_PHY_STATUS_SPD_MASK 0xc000
172#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000
173#define MII_M1011_PHY_STATUS_RESOLVED 0x0800
174#define MII_M1011_PHY_STATUS_LINK 0x0400
175
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +0200176#define MII_88E3016_PHY_SPEC_CTRL 0x10
177#define MII_88E3016_DISABLE_SCRAMBLER 0x0200
178#define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030
Andy Fleming76884672007-02-09 18:13:58 -0600179
Stefan Roese930b37e2016-02-18 10:59:07 +0100180#define MII_88E1510_GEN_CTRL_REG_1 0x14
181#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7
Ivan Bornyakovb697d9d2021-08-12 16:42:56 +0300182#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII 0x0 /* RGMII to copper */
Stefan Roese930b37e2016-02-18 10:59:07 +0100183#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */
Ivan Bornyakovb697d9d2021-08-12 16:42:56 +0300184/* RGMII to 1000BASE-X */
185#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X 0x2
186/* RGMII to 100BASE-FX */
187#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX 0x3
188/* RGMII to SGMII */
189#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII 0x4
Stefan Roese930b37e2016-02-18 10:59:07 +0100190#define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */
191
Mohammad Athari Bin Ismail020a45a2022-01-15 17:25:15 +0800192#define MII_88E1510_MSCR_2 0x15
193
Andrew Lunn0c9bcc12020-05-27 00:21:40 +0200194#define MII_VCT5_TX_RX_MDI0_COUPLING 0x10
195#define MII_VCT5_TX_RX_MDI1_COUPLING 0x11
196#define MII_VCT5_TX_RX_MDI2_COUPLING 0x12
197#define MII_VCT5_TX_RX_MDI3_COUPLING 0x13
198#define MII_VCT5_TX_RX_AMPLITUDE_MASK 0x7f00
199#define MII_VCT5_TX_RX_AMPLITUDE_SHIFT 8
200#define MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION BIT(15)
201
202#define MII_VCT5_CTRL 0x17
203#define MII_VCT5_CTRL_ENABLE BIT(15)
204#define MII_VCT5_CTRL_COMPLETE BIT(14)
205#define MII_VCT5_CTRL_TX_SAME_CHANNEL (0x0 << 11)
206#define MII_VCT5_CTRL_TX0_CHANNEL (0x4 << 11)
207#define MII_VCT5_CTRL_TX1_CHANNEL (0x5 << 11)
208#define MII_VCT5_CTRL_TX2_CHANNEL (0x6 << 11)
209#define MII_VCT5_CTRL_TX3_CHANNEL (0x7 << 11)
210#define MII_VCT5_CTRL_SAMPLES_2 (0x0 << 8)
211#define MII_VCT5_CTRL_SAMPLES_4 (0x1 << 8)
212#define MII_VCT5_CTRL_SAMPLES_8 (0x2 << 8)
213#define MII_VCT5_CTRL_SAMPLES_16 (0x3 << 8)
214#define MII_VCT5_CTRL_SAMPLES_32 (0x4 << 8)
215#define MII_VCT5_CTRL_SAMPLES_64 (0x5 << 8)
216#define MII_VCT5_CTRL_SAMPLES_128 (0x6 << 8)
217#define MII_VCT5_CTRL_SAMPLES_DEFAULT (0x6 << 8)
218#define MII_VCT5_CTRL_SAMPLES_256 (0x7 << 8)
219#define MII_VCT5_CTRL_SAMPLES_SHIFT 8
220#define MII_VCT5_CTRL_MODE_MAXIMUM_PEEK (0x0 << 6)
221#define MII_VCT5_CTRL_MODE_FIRST_LAST_PEEK (0x1 << 6)
222#define MII_VCT5_CTRL_MODE_OFFSET (0x2 << 6)
223#define MII_VCT5_CTRL_SAMPLE_POINT (0x3 << 6)
224#define MII_VCT5_CTRL_PEEK_HYST_DEFAULT 3
225
226#define MII_VCT5_SAMPLE_POINT_DISTANCE 0x18
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +0200227#define MII_VCT5_SAMPLE_POINT_DISTANCE_MAX 511
Andrew Lunn0c9bcc12020-05-27 00:21:40 +0200228#define MII_VCT5_TX_PULSE_CTRL 0x1c
229#define MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN BIT(12)
230#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS (0x0 << 10)
231#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_96nS (0x1 << 10)
232#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_64nS (0x2 << 10)
233#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS (0x3 << 10)
234#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_SHIFT 10
235#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_1000mV (0x0 << 8)
236#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_750mV (0x1 << 8)
237#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_500mV (0x2 << 8)
238#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_250mV (0x3 << 8)
239#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_SHIFT 8
240#define MII_VCT5_TX_PULSE_CTRL_MAX_AMP BIT(7)
241#define MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV (0x6 << 0)
242
Andrew Lunndb8668a2020-05-27 00:21:43 +0200243/* For TDR measurements less than 11 meters, a short pulse should be
244 * used.
245 */
246#define TDR_SHORT_CABLE_LENGTH 11
247
Andrew Lunnfc879f72020-05-10 21:12:38 +0200248#define MII_VCT7_PAIR_0_DISTANCE 0x10
249#define MII_VCT7_PAIR_1_DISTANCE 0x11
250#define MII_VCT7_PAIR_2_DISTANCE 0x12
251#define MII_VCT7_PAIR_3_DISTANCE 0x13
252
253#define MII_VCT7_RESULTS 0x14
254#define MII_VCT7_RESULTS_PAIR3_MASK 0xf000
255#define MII_VCT7_RESULTS_PAIR2_MASK 0x0f00
256#define MII_VCT7_RESULTS_PAIR1_MASK 0x00f0
257#define MII_VCT7_RESULTS_PAIR0_MASK 0x000f
258#define MII_VCT7_RESULTS_PAIR3_SHIFT 12
259#define MII_VCT7_RESULTS_PAIR2_SHIFT 8
260#define MII_VCT7_RESULTS_PAIR1_SHIFT 4
261#define MII_VCT7_RESULTS_PAIR0_SHIFT 0
262#define MII_VCT7_RESULTS_INVALID 0
263#define MII_VCT7_RESULTS_OK 1
264#define MII_VCT7_RESULTS_OPEN 2
265#define MII_VCT7_RESULTS_SAME_SHORT 3
266#define MII_VCT7_RESULTS_CROSS_SHORT 4
267#define MII_VCT7_RESULTS_BUSY 9
268
269#define MII_VCT7_CTRL 0x15
270#define MII_VCT7_CTRL_RUN_NOW BIT(15)
271#define MII_VCT7_CTRL_RUN_ANEG BIT(14)
272#define MII_VCT7_CTRL_DISABLE_CROSS BIT(13)
273#define MII_VCT7_CTRL_RUN_AFTER_BREAK_LINK BIT(12)
274#define MII_VCT7_CTRL_IN_PROGRESS BIT(11)
275#define MII_VCT7_CTRL_METERS BIT(10)
276#define MII_VCT7_CTRL_CENTIMETERS 0
277
Andrew Lunn8cf8b872017-07-30 22:41:44 +0200278#define LPA_PAUSE_FIBER 0x180
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +0200279#define LPA_PAUSE_ASYM_FIBER 0x100
280
Charles-Antoine Couret2170fef2016-07-19 11:13:11 +0200281#define NB_FIBER_STATS 1
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +0200282
Andy Fleming00db8182005-07-30 19:31:23 -0400283MODULE_DESCRIPTION("Marvell PHY driver");
284MODULE_AUTHOR("Andy Fleming");
285MODULE_LICENSE("GPL");
286
Andrew Lunnd2fa47d2015-12-30 16:28:26 +0100287struct marvell_hw_stat {
288 const char *string;
289 u8 page;
290 u8 reg;
291 u8 bits;
292};
293
294static struct marvell_hw_stat marvell_hw_stats[] = {
Charles-Antoine Couret2170fef2016-07-19 11:13:11 +0200295 { "phy_receive_errors_copper", 0, 21, 16},
Andrew Lunnd2fa47d2015-12-30 16:28:26 +0100296 { "phy_idle_errors", 0, 10, 8 },
Charles-Antoine Couret2170fef2016-07-19 11:13:11 +0200297 { "phy_receive_errors_fiber", 1, 21, 16},
Andrew Lunnd2fa47d2015-12-30 16:28:26 +0100298};
299
300struct marvell_priv {
301 u64 stats[ARRAY_SIZE(marvell_hw_stats)];
Andrew Lunn0b046802017-01-20 01:37:49 +0100302 char *hwmon_name;
303 struct device *hwmon_dev;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +0200304 bool cable_test_tdr;
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +0200305 u32 first;
306 u32 last;
307 u32 step;
308 s8 pair;
Andrew Lunnd2fa47d2015-12-30 16:28:26 +0100309};
310
Russell King424ca4c2018-01-02 10:58:48 +0000311static int marvell_read_page(struct phy_device *phydev)
Andrew Lunn6427bb22017-05-17 03:26:03 +0200312{
Russell King424ca4c2018-01-02 10:58:48 +0000313 return __phy_read(phydev, MII_MARVELL_PHY_PAGE);
314}
315
316static int marvell_write_page(struct phy_device *phydev, int page)
317{
318 return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
Andrew Lunn6427bb22017-05-17 03:26:03 +0200319}
320
321static int marvell_set_page(struct phy_device *phydev, int page)
322{
323 return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
324}
325
Andy Fleming00db8182005-07-30 19:31:23 -0400326static int marvell_ack_interrupt(struct phy_device *phydev)
327{
328 int err;
329
330 /* Clear the interrupts by reading the reg */
331 err = phy_read(phydev, MII_M1011_IEVENT);
332
333 if (err < 0)
334 return err;
335
336 return 0;
337}
338
339static int marvell_config_intr(struct phy_device *phydev)
340{
341 int err;
342
Ioana Ciornei1f6d0f22020-11-13 18:52:14 +0200343 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
344 err = marvell_ack_interrupt(phydev);
345 if (err)
346 return err;
347
Andrew Lunn23beb382017-05-17 03:26:04 +0200348 err = phy_write(phydev, MII_M1011_IMASK,
349 MII_M1011_IMASK_INIT);
Ioana Ciornei1f6d0f22020-11-13 18:52:14 +0200350 } else {
Andrew Lunn23beb382017-05-17 03:26:04 +0200351 err = phy_write(phydev, MII_M1011_IMASK,
352 MII_M1011_IMASK_CLEAR);
Ioana Ciornei1f6d0f22020-11-13 18:52:14 +0200353 if (err)
354 return err;
355
356 err = marvell_ack_interrupt(phydev);
357 }
Andy Fleming00db8182005-07-30 19:31:23 -0400358
359 return err;
360}
361
Ioana Ciorneia0723b32020-11-13 18:52:13 +0200362static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
363{
364 int irq_status;
365
366 irq_status = phy_read(phydev, MII_M1011_IEVENT);
367 if (irq_status < 0) {
368 phy_error(phydev);
369 return IRQ_NONE;
370 }
371
372 if (!(irq_status & MII_M1011_IMASK_INIT))
373 return IRQ_NONE;
374
375 phy_trigger_machine(phydev);
376
377 return IRQ_HANDLED;
378}
379
David Thomson239aa552015-07-10 16:28:25 +1200380static int marvell_set_polarity(struct phy_device *phydev, int polarity)
381{
Russell Kingfeb938f2021-06-03 14:01:10 +0100382 u16 val;
David Thomson239aa552015-07-10 16:28:25 +1200383
David Thomson239aa552015-07-10 16:28:25 +1200384 switch (polarity) {
385 case ETH_TP_MDI:
Russell Kingfeb938f2021-06-03 14:01:10 +0100386 val = MII_M1011_PHY_SCR_MDI;
David Thomson239aa552015-07-10 16:28:25 +1200387 break;
388 case ETH_TP_MDI_X:
Russell Kingfeb938f2021-06-03 14:01:10 +0100389 val = MII_M1011_PHY_SCR_MDI_X;
David Thomson239aa552015-07-10 16:28:25 +1200390 break;
391 case ETH_TP_MDI_AUTO:
392 case ETH_TP_MDI_INVALID:
393 default:
Russell Kingfeb938f2021-06-03 14:01:10 +0100394 val = MII_M1011_PHY_SCR_AUTO_CROSS;
David Thomson239aa552015-07-10 16:28:25 +1200395 break;
396 }
397
Russell Kingfeb938f2021-06-03 14:01:10 +0100398 return phy_modify_changed(phydev, MII_M1011_PHY_SCR,
399 MII_M1011_PHY_SCR_AUTO_CROSS, val);
David Thomson239aa552015-07-10 16:28:25 +1200400}
401
Andy Fleming00db8182005-07-30 19:31:23 -0400402static int marvell_config_aneg(struct phy_device *phydev)
403{
Florian Fainellid6ab9332018-09-25 11:28:46 -0700404 int changed = 0;
Andy Fleming00db8182005-07-30 19:31:23 -0400405 int err;
406
Raju Lakkaraju4e26c5c2016-11-29 15:16:49 +0530407 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
Andy Fleming76884672007-02-09 18:13:58 -0600408 if (err < 0)
409 return err;
410
Florian Fainellid6ab9332018-09-25 11:28:46 -0700411 changed = err;
412
Andy Fleming76884672007-02-09 18:13:58 -0600413 err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
414 MII_M1111_PHY_LED_DIRECT);
415 if (err < 0)
416 return err;
Andy Fleming00db8182005-07-30 19:31:23 -0400417
418 err = genphy_config_aneg(phydev);
Anton Vorontsov8ff44982009-09-09 16:01:30 +0000419 if (err < 0)
420 return err;
Andy Fleming00db8182005-07-30 19:31:23 -0400421
Florian Fainellid6ab9332018-09-25 11:28:46 -0700422 if (phydev->autoneg != AUTONEG_ENABLE || changed) {
Andrew Lunn0c3439b2017-05-17 03:25:59 +0200423 /* A write to speed/duplex bits (that is performed by
Anton Vorontsov8ff44982009-09-09 16:01:30 +0000424 * genphy_config_aneg() call above) must be followed by
425 * a software reset. Otherwise, the write has no effect.
426 */
Andrew Lunn34386342017-07-30 22:41:45 +0200427 err = genphy_soft_reset(phydev);
Anton Vorontsov8ff44982009-09-09 16:01:30 +0000428 if (err < 0)
429 return err;
430 }
431
432 return 0;
Andy Fleming00db8182005-07-30 19:31:23 -0400433}
434
Andrew Lunnf2899782017-05-23 17:49:13 +0200435static int m88e1101_config_aneg(struct phy_device *phydev)
436{
437 int err;
438
439 /* This Marvell PHY has an errata which requires
440 * that certain registers get written in order
441 * to restart autonegotiation
442 */
Andrew Lunn34386342017-07-30 22:41:45 +0200443 err = genphy_soft_reset(phydev);
Andrew Lunnf2899782017-05-23 17:49:13 +0200444 if (err < 0)
445 return err;
446
447 err = phy_write(phydev, 0x1d, 0x1f);
448 if (err < 0)
449 return err;
450
451 err = phy_write(phydev, 0x1e, 0x200c);
452 if (err < 0)
453 return err;
454
455 err = phy_write(phydev, 0x1d, 0x5);
456 if (err < 0)
457 return err;
458
459 err = phy_write(phydev, 0x1e, 0);
460 if (err < 0)
461 return err;
462
463 err = phy_write(phydev, 0x1e, 0x100);
464 if (err < 0)
465 return err;
466
467 return marvell_config_aneg(phydev);
468}
469
Dan Murphy5cd119d2020-06-05 09:01:06 -0500470#if IS_ENABLED(CONFIG_OF_MDIO)
Andrew Lunn0c3439b2017-05-17 03:25:59 +0200471/* Set and/or override some configuration registers based on the
David Daneycf41a512010-11-19 12:13:18 +0000472 * marvell,reg-init property stored in the of_node for the phydev.
473 *
474 * marvell,reg-init = <reg-page reg mask value>,...;
475 *
476 * There may be one or more sets of <reg-page reg mask value>:
477 *
478 * reg-page: which register bank to use.
479 * reg: the register.
480 * mask: if non-zero, ANDed with existing register value.
481 * value: ORed with the masked value and written to the regiser.
482 *
483 */
484static int marvell_of_reg_init(struct phy_device *phydev)
485{
486 const __be32 *paddr;
Russell King424ca4c2018-01-02 10:58:48 +0000487 int len, i, saved_page, current_page, ret = 0;
David Daneycf41a512010-11-19 12:13:18 +0000488
Andrew Lunne5a03bf2016-01-06 20:11:16 +0100489 if (!phydev->mdio.dev.of_node)
David Daneycf41a512010-11-19 12:13:18 +0000490 return 0;
491
Andrew Lunne5a03bf2016-01-06 20:11:16 +0100492 paddr = of_get_property(phydev->mdio.dev.of_node,
493 "marvell,reg-init", &len);
David Daneycf41a512010-11-19 12:13:18 +0000494 if (!paddr || len < (4 * sizeof(*paddr)))
495 return 0;
496
Russell King424ca4c2018-01-02 10:58:48 +0000497 saved_page = phy_save_page(phydev);
David Daneycf41a512010-11-19 12:13:18 +0000498 if (saved_page < 0)
Russell King424ca4c2018-01-02 10:58:48 +0000499 goto err;
David Daneycf41a512010-11-19 12:13:18 +0000500 current_page = saved_page;
501
David Daneycf41a512010-11-19 12:13:18 +0000502 len /= sizeof(*paddr);
503 for (i = 0; i < len - 3; i += 4) {
Andrew Lunn6427bb22017-05-17 03:26:03 +0200504 u16 page = be32_to_cpup(paddr + i);
David Daneycf41a512010-11-19 12:13:18 +0000505 u16 reg = be32_to_cpup(paddr + i + 1);
506 u16 mask = be32_to_cpup(paddr + i + 2);
507 u16 val_bits = be32_to_cpup(paddr + i + 3);
508 int val;
509
Andrew Lunn6427bb22017-05-17 03:26:03 +0200510 if (page != current_page) {
511 current_page = page;
Russell King424ca4c2018-01-02 10:58:48 +0000512 ret = marvell_write_page(phydev, page);
David Daneycf41a512010-11-19 12:13:18 +0000513 if (ret < 0)
514 goto err;
515 }
516
517 val = 0;
518 if (mask) {
Russell King424ca4c2018-01-02 10:58:48 +0000519 val = __phy_read(phydev, reg);
David Daneycf41a512010-11-19 12:13:18 +0000520 if (val < 0) {
521 ret = val;
522 goto err;
523 }
524 val &= mask;
525 }
526 val |= val_bits;
527
Russell King424ca4c2018-01-02 10:58:48 +0000528 ret = __phy_write(phydev, reg, val);
David Daneycf41a512010-11-19 12:13:18 +0000529 if (ret < 0)
530 goto err;
David Daneycf41a512010-11-19 12:13:18 +0000531 }
532err:
Russell King424ca4c2018-01-02 10:58:48 +0000533 return phy_restore_page(phydev, saved_page, ret);
David Daneycf41a512010-11-19 12:13:18 +0000534}
535#else
536static int marvell_of_reg_init(struct phy_device *phydev)
537{
538 return 0;
539}
540#endif /* CONFIG_OF_MDIO */
541
Andrew Lunn864dc722017-07-30 22:41:48 +0200542static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
Sergei Poselenov140bc922009-04-07 02:01:41 +0000543{
Russell King424ca4c2018-01-02 10:58:48 +0000544 int mscr;
Andrew Lunn864dc722017-07-30 22:41:48 +0200545
546 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Russell King424ca4c2018-01-02 10:58:48 +0000547 mscr = MII_88E1121_PHY_MSCR_RX_DELAY |
548 MII_88E1121_PHY_MSCR_TX_DELAY;
Andrew Lunn864dc722017-07-30 22:41:48 +0200549 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
Russell King424ca4c2018-01-02 10:58:48 +0000550 mscr = MII_88E1121_PHY_MSCR_RX_DELAY;
Andrew Lunn864dc722017-07-30 22:41:48 +0200551 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
Russell King424ca4c2018-01-02 10:58:48 +0000552 mscr = MII_88E1121_PHY_MSCR_TX_DELAY;
553 else
554 mscr = 0;
Andrew Lunn864dc722017-07-30 22:41:48 +0200555
Pavel Parkhomenkofe4f57b2022-02-05 23:39:32 +0300556 return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,
557 MII_88E1121_PHY_MSCR_REG,
558 MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
Andrew Lunn864dc722017-07-30 22:41:48 +0200559}
560
561static int m88e1121_config_aneg(struct phy_device *phydev)
562{
Florian Fainellid6ab9332018-09-25 11:28:46 -0700563 int changed = 0;
Andrew Lunn864dc722017-07-30 22:41:48 +0200564 int err = 0;
565
566 if (phy_interface_is_rgmii(phydev)) {
567 err = m88e1121_config_aneg_rgmii_delays(phydev);
Russell Kingfea23fb2018-01-02 10:58:58 +0000568 if (err < 0)
Andrew Lunn864dc722017-07-30 22:41:48 +0200569 return err;
570 }
571
Pavel Parkhomenkofe4f57b2022-02-05 23:39:32 +0300572 changed = err;
573
Andrew Lunnfecd5e92017-07-30 22:41:49 +0200574 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
Sergei Poselenov140bc922009-04-07 02:01:41 +0000575 if (err < 0)
576 return err;
577
Pavel Parkhomenkofe4f57b2022-02-05 23:39:32 +0300578 changed |= err;
Florian Fainellid6ab9332018-09-25 11:28:46 -0700579
580 err = genphy_config_aneg(phydev);
581 if (err < 0)
582 return err;
583
David S. Miller4b1bd692018-09-25 22:41:31 -0700584 if (phydev->autoneg != AUTONEG_ENABLE || changed) {
Florian Fainellid6ab9332018-09-25 11:28:46 -0700585 /* A software reset is used to ensure a "commit" of the
586 * changes is done.
587 */
588 err = genphy_soft_reset(phydev);
589 if (err < 0)
590 return err;
591 }
592
593 return 0;
Sergei Poselenov140bc922009-04-07 02:01:41 +0000594}
595
Cyril Chemparathy337ac9d2010-10-29 13:50:25 -0700596static int m88e1318_config_aneg(struct phy_device *phydev)
Cyril Chemparathy3ff1c252010-08-03 19:36:06 -0700597{
Russell King424ca4c2018-01-02 10:58:48 +0000598 int err;
Cyril Chemparathy3ff1c252010-08-03 19:36:06 -0700599
Russell King424ca4c2018-01-02 10:58:48 +0000600 err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
601 MII_88E1318S_PHY_MSCR1_REG,
602 0, MII_88E1318S_PHY_MSCR1_PAD_ODD);
Cyril Chemparathy3ff1c252010-08-03 19:36:06 -0700603 if (err < 0)
604 return err;
605
606 return m88e1121_config_aneg(phydev);
607}
608
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200609/**
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100610 * linkmode_adv_to_fiber_adv_t
611 * @advertise: the linkmode advertisement settings
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200612 *
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100613 * A small helper function that translates linkmode advertisement
614 * settings to phy autonegotiation advertisements for the MII_ADV
615 * register for fiber link.
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200616 */
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100617static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise)
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200618{
619 u32 result = 0;
620
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100621 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise))
Russell King20ecf422019-12-17 13:39:42 +0000622 result |= ADVERTISE_1000XHALF;
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100623 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise))
Russell King20ecf422019-12-17 13:39:42 +0000624 result |= ADVERTISE_1000XFULL;
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200625
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100626 if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) &&
627 linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
Russell King20ecf422019-12-17 13:39:42 +0000628 result |= ADVERTISE_1000XPSE_ASYM;
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100629 else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
Russell King20ecf422019-12-17 13:39:42 +0000630 result |= ADVERTISE_1000XPAUSE;
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200631
632 return result;
633}
634
635/**
636 * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR
637 * @phydev: target phy_device struct
638 *
639 * Description: If auto-negotiation is enabled, we configure the
640 * advertising, and then restart auto-negotiation. If it is not
641 * enabled, then we write the BMCR. Adapted for fiber link in
642 * some Marvell's devices.
643 */
644static int marvell_config_aneg_fiber(struct phy_device *phydev)
645{
646 int changed = 0;
647 int err;
Russell King9f4bae72019-12-17 13:39:47 +0000648 u16 adv;
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200649
650 if (phydev->autoneg != AUTONEG_ENABLE)
651 return genphy_setup_forced(phydev);
652
653 /* Only allow advertising what this PHY supports */
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100654 linkmode_and(phydev->advertising, phydev->advertising,
655 phydev->supported);
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200656
Russell King9f4bae72019-12-17 13:39:47 +0000657 adv = linkmode_adv_to_fiber_adv_t(phydev->advertising);
658
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200659 /* Setup fiber advertisement */
Russell King9f4bae72019-12-17 13:39:47 +0000660 err = phy_modify_changed(phydev, MII_ADVERTISE,
661 ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |
662 ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,
663 adv);
664 if (err < 0)
665 return err;
666 if (err > 0)
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200667 changed = 1;
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200668
Russell Kingb5abac22019-12-17 13:39:52 +0000669 return genphy_check_and_restart_aneg(phydev, changed);
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200670}
671
Robert Hancock18870232020-10-28 11:15:40 -0600672static int m88e1111_config_aneg(struct phy_device *phydev)
673{
674 int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
675 int err;
676
677 if (extsr < 0)
678 return extsr;
679
680 /* If not using SGMII or copper 1000BaseX modes, use normal process.
681 * Steps below are only required for these modes.
682 */
683 if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
684 (extsr & MII_M1111_HWCFG_MODE_MASK) !=
685 MII_M1111_HWCFG_MODE_COPPER_1000X_AN)
686 return marvell_config_aneg(phydev);
687
688 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
689 if (err < 0)
690 goto error;
691
692 /* Configure the copper link first */
693 err = marvell_config_aneg(phydev);
694 if (err < 0)
695 goto error;
696
Robert Hancock18870232020-10-28 11:15:40 -0600697 /* Then the fiber link */
698 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
699 if (err < 0)
700 goto error;
701
Robert Hancock06b334f2021-02-16 14:53:30 -0600702 if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
703 /* Do not touch the fiber advertisement if we're in copper->sgmii mode.
704 * Just ensure that SGMII-side autonegotiation is enabled.
705 * If we switched from some other mode to SGMII it may not be.
706 */
707 err = genphy_check_and_restart_aneg(phydev, false);
708 else
709 err = marvell_config_aneg_fiber(phydev);
Robert Hancock18870232020-10-28 11:15:40 -0600710 if (err < 0)
711 goto error;
712
713 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
714
715error:
716 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
717 return err;
718}
719
Michal Simek10e24caa2013-05-30 20:08:27 +0000720static int m88e1510_config_aneg(struct phy_device *phydev)
721{
722 int err;
723
Andrew Lunn52295662017-05-25 21:42:08 +0200724 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200725 if (err < 0)
726 goto error;
727
728 /* Configure the copper link first */
Michal Simek10e24caa2013-05-30 20:08:27 +0000729 err = m88e1318_config_aneg(phydev);
730 if (err < 0)
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200731 goto error;
Michal Simek10e24caa2013-05-30 20:08:27 +0000732
Russell Kingde9c4e02017-12-13 09:22:03 +0000733 /* Do not touch the fiber page if we're in copper->sgmii mode */
734 if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
735 return 0;
736
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200737 /* Then the fiber link */
Andrew Lunn52295662017-05-25 21:42:08 +0200738 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200739 if (err < 0)
740 goto error;
741
742 err = marvell_config_aneg_fiber(phydev);
743 if (err < 0)
744 goto error;
745
Andrew Lunn52295662017-05-25 21:42:08 +0200746 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200747
748error:
Andrew Lunn52295662017-05-25 21:42:08 +0200749 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret78301eb2016-07-19 11:13:12 +0200750 return err;
Clemens Gruber79be1a12016-02-15 23:46:45 +0100751}
752
Wang Dongsheng07777242018-07-01 23:15:46 -0700753static void marvell_config_led(struct phy_device *phydev)
754{
755 u16 def_config;
756 int err;
757
758 switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) {
759 /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
760 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R):
761 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S):
762 def_config = MII_88E1121_PHY_LED_DEF;
763 break;
764 /* Default PHY LED config:
765 * LED[0] .. 1000Mbps Link
766 * LED[1] .. 100Mbps Link
767 * LED[2] .. Blink, Activity
768 */
769 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510):
Jian Shena93f7fe2019-04-22 21:52:23 +0800770 if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE)
771 def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE;
772 else
773 def_config = MII_88E1510_PHY_LED_DEF;
Wang Dongsheng07777242018-07-01 23:15:46 -0700774 break;
775 default:
776 return;
777 }
778
779 err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,
780 def_config);
781 if (err < 0)
Andrew Lunnab2a6052018-09-29 23:04:10 +0200782 phydev_warn(phydev, "Fail to config marvell phy LED.\n");
Wang Dongsheng07777242018-07-01 23:15:46 -0700783}
784
Clemens Gruber79be1a12016-02-15 23:46:45 +0100785static int marvell_config_init(struct phy_device *phydev)
786{
Bhaskar Chowdhury85bec4b2020-10-29 15:25:25 +0530787 /* Set default LED */
Wang Dongsheng07777242018-07-01 23:15:46 -0700788 marvell_config_led(phydev);
789
Clemens Gruber79be1a12016-02-15 23:46:45 +0100790 /* Set registers from marvell,reg-init DT property */
Michal Simek10e24caa2013-05-30 20:08:27 +0000791 return marvell_of_reg_init(phydev);
792}
793
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +0200794static int m88e3016_config_init(struct phy_device *phydev)
795{
Russell Kingfea23fb2018-01-02 10:58:58 +0000796 int ret;
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +0200797
798 /* Enable Scrambler and Auto-Crossover */
Russell Kingfea23fb2018-01-02 10:58:58 +0000799 ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL,
Russell Kingf1028522018-01-05 16:07:10 +0000800 MII_88E3016_DISABLE_SCRAMBLER,
Russell Kingfea23fb2018-01-02 10:58:58 +0000801 MII_88E3016_AUTO_MDIX_CROSSOVER);
802 if (ret < 0)
803 return ret;
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +0200804
Clemens Gruber79be1a12016-02-15 23:46:45 +0100805 return marvell_config_init(phydev);
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +0200806}
807
Andrew Lunn865b813a2017-07-30 22:41:47 +0200808static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,
809 u16 mode,
810 int fibre_copper_auto)
811{
Andrew Lunn865b813a2017-07-30 22:41:47 +0200812 if (fibre_copper_auto)
Russell Kingfea23fb2018-01-02 10:58:58 +0000813 mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
Andrew Lunn865b813a2017-07-30 22:41:47 +0200814
Russell Kingfea23fb2018-01-02 10:58:58 +0000815 return phy_modify(phydev, MII_M1111_PHY_EXT_SR,
Russell Kingf1028522018-01-05 16:07:10 +0000816 MII_M1111_HWCFG_MODE_MASK |
817 MII_M1111_HWCFG_FIBER_COPPER_AUTO |
818 MII_M1111_HWCFG_FIBER_COPPER_RES,
Russell Kingfea23fb2018-01-02 10:58:58 +0000819 mode);
Andrew Lunn865b813a2017-07-30 22:41:47 +0200820}
821
Andrew Lunn61111592017-07-30 22:41:46 +0200822static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)
Kim Phillips895ee682007-06-05 18:46:47 +0800823{
Russell Kingfea23fb2018-01-02 10:58:58 +0000824 int delay;
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200825
Weihang Li16d4d652021-06-16 18:01:26 +0800826 switch (phydev->interface) {
827 case PHY_INTERFACE_MODE_RGMII_ID:
Russell Kingfea23fb2018-01-02 10:58:58 +0000828 delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;
Weihang Li16d4d652021-06-16 18:01:26 +0800829 break;
830 case PHY_INTERFACE_MODE_RGMII_RXID:
Russell Kingfea23fb2018-01-02 10:58:58 +0000831 delay = MII_M1111_RGMII_RX_DELAY;
Weihang Li16d4d652021-06-16 18:01:26 +0800832 break;
833 case PHY_INTERFACE_MODE_RGMII_TXID:
Russell Kingfea23fb2018-01-02 10:58:58 +0000834 delay = MII_M1111_RGMII_TX_DELAY;
Weihang Li16d4d652021-06-16 18:01:26 +0800835 break;
836 default:
Russell Kingfea23fb2018-01-02 10:58:58 +0000837 delay = 0;
Weihang Li16d4d652021-06-16 18:01:26 +0800838 break;
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200839 }
840
Russell Kingfea23fb2018-01-02 10:58:58 +0000841 return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
Russell Kingf1028522018-01-05 16:07:10 +0000842 MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY,
Russell Kingfea23fb2018-01-02 10:58:58 +0000843 delay);
Andrew Lunn61111592017-07-30 22:41:46 +0200844}
845
846static int m88e1111_config_init_rgmii(struct phy_device *phydev)
847{
848 int temp;
849 int err;
850
851 err = m88e1111_config_init_rgmii_delays(phydev);
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200852 if (err < 0)
853 return err;
854
855 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
856 if (temp < 0)
857 return temp;
858
859 temp &= ~(MII_M1111_HWCFG_MODE_MASK);
860
861 if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
862 temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
863 else
864 temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
865
866 return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
867}
868
869static int m88e1111_config_init_sgmii(struct phy_device *phydev)
870{
871 int err;
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200872
Andrew Lunn865b813a2017-07-30 22:41:47 +0200873 err = m88e1111_config_init_hwcfg_mode(
874 phydev,
875 MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
876 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200877 if (err < 0)
878 return err;
879
880 /* make sure copper is selected */
Andrew Lunn52295662017-05-25 21:42:08 +0200881 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200882}
883
884static int m88e1111_config_init_rtbi(struct phy_device *phydev)
885{
Andrew Lunn61111592017-07-30 22:41:46 +0200886 int err;
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200887
Andrew Lunn61111592017-07-30 22:41:46 +0200888 err = m88e1111_config_init_rgmii_delays(phydev);
Russell Kingfea23fb2018-01-02 10:58:58 +0000889 if (err < 0)
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200890 return err;
891
Andrew Lunn865b813a2017-07-30 22:41:47 +0200892 err = m88e1111_config_init_hwcfg_mode(
893 phydev,
894 MII_M1111_HWCFG_MODE_RTBI,
895 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200896 if (err < 0)
897 return err;
898
899 /* soft reset */
Andrew Lunn34386342017-07-30 22:41:45 +0200900 err = genphy_soft_reset(phydev);
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200901 if (err < 0)
902 return err;
903
Andrew Lunn865b813a2017-07-30 22:41:47 +0200904 return m88e1111_config_init_hwcfg_mode(
905 phydev,
906 MII_M1111_HWCFG_MODE_RTBI,
907 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200908}
909
Robert Hancock18870232020-10-28 11:15:40 -0600910static int m88e1111_config_init_1000basex(struct phy_device *phydev)
911{
912 int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
913 int err, mode;
914
915 if (extsr < 0)
916 return extsr;
917
918 /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */
919 mode = extsr & MII_M1111_HWCFG_MODE_MASK;
920 if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) {
921 err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
922 MII_M1111_HWCFG_MODE_MASK |
923 MII_M1111_HWCFG_SERIAL_AN_BYPASS,
924 MII_M1111_HWCFG_MODE_COPPER_1000X_AN |
925 MII_M1111_HWCFG_SERIAL_AN_BYPASS);
926 if (err < 0)
927 return err;
928 }
929 return 0;
930}
931
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200932static int m88e1111_config_init(struct phy_device *phydev)
933{
934 int err;
935
Florian Fainelli32a64162015-05-26 12:19:59 -0700936 if (phy_interface_is_rgmii(phydev)) {
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200937 err = m88e1111_config_init_rgmii(phydev);
Russell Kingfea23fb2018-01-02 10:58:58 +0000938 if (err < 0)
Kim Phillips895ee682007-06-05 18:46:47 +0800939 return err;
940 }
941
Kapil Juneja4117b5b2007-05-11 18:25:18 -0500942 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200943 err = m88e1111_config_init_sgmii(phydev);
Madalin Bucur07151bc2015-08-07 17:07:50 +0800944 if (err < 0)
945 return err;
Kapil Juneja4117b5b2007-05-11 18:25:18 -0500946 }
947
Liu Yu-B132015f8cbc12010-01-13 22:13:19 +0000948 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
Andrew Lunne1dde8d2017-05-17 03:26:02 +0200949 err = m88e1111_config_init_rtbi(phydev);
Liu Yu-B132015f8cbc12010-01-13 22:13:19 +0000950 if (err < 0)
951 return err;
952 }
953
Robert Hancock18870232020-10-28 11:15:40 -0600954 if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) {
955 err = m88e1111_config_init_1000basex(phydev);
956 if (err < 0)
957 return err;
958 }
959
David Daneycf41a512010-11-19 12:13:18 +0000960 err = marvell_of_reg_init(phydev);
961 if (err < 0)
962 return err;
Liu Yu-B132015f8cbc12010-01-13 22:13:19 +0000963
Andrew Lunn34386342017-07-30 22:41:45 +0200964 return genphy_soft_reset(phydev);
Kim Phillips895ee682007-06-05 18:46:47 +0800965}
966
Heiner Kallweit5c6bc512019-10-28 20:53:25 +0100967static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)
968{
969 int val, cnt, enable;
970
971 val = phy_read(phydev, MII_M1111_PHY_EXT_CR);
972 if (val < 0)
973 return val;
974
975 enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val);
976 cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1;
977
978 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
979
980 return 0;
981}
982
983static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)
984{
Maxim Kochetkove7679c52021-04-22 13:46:44 +0300985 int val, err;
Heiner Kallweit5c6bc512019-10-28 20:53:25 +0100986
987 if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX)
988 return -E2BIG;
989
Maxim Kochetkove7679c52021-04-22 13:46:44 +0300990 if (!cnt) {
991 err = phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,
992 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);
993 } else {
994 val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;
995 val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);
Heiner Kallweit5c6bc512019-10-28 20:53:25 +0100996
Maxim Kochetkove7679c52021-04-22 13:46:44 +0300997 err = phy_modify(phydev, MII_M1111_PHY_EXT_CR,
998 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |
999 MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,
1000 val);
1001 }
Heiner Kallweit5c6bc512019-10-28 20:53:25 +01001002
Maxim Kochetkove7679c52021-04-22 13:46:44 +03001003 if (err < 0)
1004 return err;
1005
1006 return genphy_soft_reset(phydev);
Heiner Kallweit5c6bc512019-10-28 20:53:25 +01001007}
1008
1009static int m88e1111_get_tunable(struct phy_device *phydev,
1010 struct ethtool_tunable *tuna, void *data)
1011{
1012 switch (tuna->id) {
1013 case ETHTOOL_PHY_DOWNSHIFT:
1014 return m88e1111_get_downshift(phydev, data);
1015 default:
1016 return -EOPNOTSUPP;
1017 }
1018}
1019
1020static int m88e1111_set_tunable(struct phy_device *phydev,
1021 struct ethtool_tunable *tuna, const void *data)
1022{
1023 switch (tuna->id) {
1024 case ETHTOOL_PHY_DOWNSHIFT:
1025 return m88e1111_set_downshift(phydev, *(const u8 *)data);
1026 default:
1027 return -EOPNOTSUPP;
1028 }
1029}
1030
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001031static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data)
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001032{
1033 int val, cnt, enable;
1034
1035 val = phy_read(phydev, MII_M1011_PHY_SCR);
1036 if (val < 0)
1037 return val;
1038
1039 enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val);
Heiner Kallweitf8d975b2019-10-28 20:52:22 +01001040 cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1;
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001041
1042 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
1043
1044 return 0;
1045}
1046
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001047static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt)
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001048{
Maxim Kochetkov990875b2021-04-22 13:46:43 +03001049 int val, err;
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001050
1051 if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)
1052 return -E2BIG;
1053
Maxim Kochetkov990875b2021-04-22 13:46:43 +03001054 if (!cnt) {
1055 err = phy_clear_bits(phydev, MII_M1011_PHY_SCR,
1056 MII_M1011_PHY_SCR_DOWNSHIFT_EN);
1057 } else {
1058 val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;
1059 val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001060
Maxim Kochetkov990875b2021-04-22 13:46:43 +03001061 err = phy_modify(phydev, MII_M1011_PHY_SCR,
1062 MII_M1011_PHY_SCR_DOWNSHIFT_EN |
1063 MII_M1011_PHY_SCR_DOWNSHIFT_MASK,
1064 val);
1065 }
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001066
Maxim Kochetkov990875b2021-04-22 13:46:43 +03001067 if (err < 0)
1068 return err;
1069
1070 return genphy_soft_reset(phydev);
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001071}
1072
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001073static int m88e1011_get_tunable(struct phy_device *phydev,
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001074 struct ethtool_tunable *tuna, void *data)
1075{
1076 switch (tuna->id) {
1077 case ETHTOOL_PHY_DOWNSHIFT:
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001078 return m88e1011_get_downshift(phydev, data);
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001079 default:
1080 return -EOPNOTSUPP;
1081 }
1082}
1083
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001084static int m88e1011_set_tunable(struct phy_device *phydev,
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001085 struct ethtool_tunable *tuna, const void *data)
1086{
1087 switch (tuna->id) {
1088 case ETHTOOL_PHY_DOWNSHIFT:
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001089 return m88e1011_set_downshift(phydev, *(const u8 *)data);
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001090 default:
1091 return -EOPNOTSUPP;
1092 }
1093}
1094
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03001095static int m88e1112_config_init(struct phy_device *phydev)
1096{
1097 int err;
1098
1099 err = m88e1011_set_downshift(phydev, 3);
1100 if (err < 0)
1101 return err;
1102
1103 return m88e1111_config_init(phydev);
1104}
1105
1106static int m88e1111gbe_config_init(struct phy_device *phydev)
1107{
1108 int err;
1109
1110 err = m88e1111_set_downshift(phydev, 3);
1111 if (err < 0)
1112 return err;
1113
1114 return m88e1111_config_init(phydev);
1115}
1116
1117static int marvell_1011gbe_config_init(struct phy_device *phydev)
1118{
1119 int err;
1120
1121 err = m88e1011_set_downshift(phydev, 3);
1122 if (err < 0)
1123 return err;
1124
1125 return marvell_config_init(phydev);
1126}
Heiner Kallweite2d861c2019-10-19 15:58:19 +02001127static int m88e1116r_config_init(struct phy_device *phydev)
1128{
1129 int err;
1130
1131 err = genphy_soft_reset(phydev);
1132 if (err < 0)
1133 return err;
1134
1135 msleep(500);
1136
1137 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
1138 if (err < 0)
1139 return err;
1140
1141 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
1142 if (err < 0)
1143 return err;
1144
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001145 err = m88e1011_set_downshift(phydev, 8);
Heiner Kallweite2d861c2019-10-19 15:58:19 +02001146 if (err < 0)
1147 return err;
1148
1149 if (phy_interface_is_rgmii(phydev)) {
1150 err = m88e1121_config_aneg_rgmii_delays(phydev);
1151 if (err < 0)
1152 return err;
1153 }
1154
1155 err = genphy_soft_reset(phydev);
1156 if (err < 0)
1157 return err;
1158
1159 return marvell_config_init(phydev);
1160}
1161
Esben Haabendaldd9a1222018-04-05 22:40:29 +02001162static int m88e1318_config_init(struct phy_device *phydev)
1163{
1164 if (phy_interrupt_is_valid(phydev)) {
1165 int err = phy_modify_paged(
1166 phydev, MII_MARVELL_LED_PAGE,
1167 MII_88E1318S_PHY_LED_TCR,
1168 MII_88E1318S_PHY_LED_TCR_FORCE_INT,
1169 MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
1170 MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
1171 if (err < 0)
1172 return err;
1173 }
1174
Wang Dongsheng07777242018-07-01 23:15:46 -07001175 return marvell_config_init(phydev);
Esben Haabendaldd9a1222018-04-05 22:40:29 +02001176}
1177
Clemens Gruber407353e2016-02-23 20:16:58 +01001178static int m88e1510_config_init(struct phy_device *phydev)
1179{
1180 int err;
Clemens Gruber407353e2016-02-23 20:16:58 +01001181
1182 /* SGMII-to-Copper mode initialization */
1183 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
1184 /* Select page 18 */
Andrew Lunn6427bb22017-05-17 03:26:03 +02001185 err = marvell_set_page(phydev, 18);
Clemens Gruber407353e2016-02-23 20:16:58 +01001186 if (err < 0)
1187 return err;
1188
1189 /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
Russell Kingfea23fb2018-01-02 10:58:58 +00001190 err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
Russell Kingf1028522018-01-05 16:07:10 +00001191 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,
Russell Kingfea23fb2018-01-02 10:58:58 +00001192 MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII);
Clemens Gruber407353e2016-02-23 20:16:58 +01001193 if (err < 0)
1194 return err;
1195
1196 /* PHY reset is necessary after changing MODE[2:0] */
Yejune Deng832913c2020-11-30 18:41:35 +08001197 err = phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,
1198 MII_88E1510_GEN_CTRL_REG_1_RESET);
Clemens Gruber407353e2016-02-23 20:16:58 +01001199 if (err < 0)
1200 return err;
1201
1202 /* Reset page selection */
Andrew Lunn52295662017-05-25 21:42:08 +02001203 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Clemens Gruber407353e2016-02-23 20:16:58 +01001204 if (err < 0)
1205 return err;
1206 }
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03001207 err = m88e1011_set_downshift(phydev, 3);
1208 if (err < 0)
1209 return err;
Clemens Gruber407353e2016-02-23 20:16:58 +01001210
Esben Haabendaldd9a1222018-04-05 22:40:29 +02001211 return m88e1318_config_init(phydev);
Clemens Gruber407353e2016-02-23 20:16:58 +01001212}
1213
Ron Madrid605f1962008-11-06 09:05:26 +00001214static int m88e1118_config_aneg(struct phy_device *phydev)
1215{
1216 int err;
1217
Andrew Lunnfecd5e92017-07-30 22:41:49 +02001218 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
Ron Madrid605f1962008-11-06 09:05:26 +00001219 if (err < 0)
1220 return err;
1221
1222 err = genphy_config_aneg(phydev);
Pavel Parkhomenkoaec12832022-02-06 00:49:51 +03001223 if (err < 0)
1224 return err;
1225
1226 return genphy_soft_reset(phydev);
Ron Madrid605f1962008-11-06 09:05:26 +00001227}
1228
1229static int m88e1118_config_init(struct phy_device *phydev)
1230{
Russell King (Oracle)5b8f9702022-01-04 16:38:13 +00001231 u16 leds;
Ron Madrid605f1962008-11-06 09:05:26 +00001232 int err;
1233
Ron Madrid605f1962008-11-06 09:05:26 +00001234 /* Enable 1000 Mbit */
Russell King (Oracle)5b8f9702022-01-04 16:38:13 +00001235 err = phy_write_paged(phydev, MII_MARVELL_MSCR_PAGE,
1236 MII_88E1121_PHY_MSCR_REG, 0x1070);
Ron Madrid605f1962008-11-06 09:05:26 +00001237 if (err < 0)
1238 return err;
1239
Russell King (Oracle)f22725c2022-01-04 16:38:19 +00001240 if (phy_interface_is_rgmii(phydev)) {
1241 err = m88e1121_config_aneg_rgmii_delays(phydev);
1242 if (err < 0)
1243 return err;
1244 }
1245
Ron Madrid605f1962008-11-06 09:05:26 +00001246 /* Adjust LED Control */
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10001247 if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
Russell King (Oracle)5b8f9702022-01-04 16:38:13 +00001248 leds = 0x1100;
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10001249 else
Russell King (Oracle)5b8f9702022-01-04 16:38:13 +00001250 leds = 0x021e;
1251
1252 err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 0x10, leds);
Ron Madrid605f1962008-11-06 09:05:26 +00001253 if (err < 0)
1254 return err;
1255
David Daneycf41a512010-11-19 12:13:18 +00001256 err = marvell_of_reg_init(phydev);
1257 if (err < 0)
1258 return err;
1259
Russell King (Oracle)5b8f9702022-01-04 16:38:13 +00001260 /* Reset page register */
Andrew Lunn52295662017-05-25 21:42:08 +02001261 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Ron Madrid605f1962008-11-06 09:05:26 +00001262 if (err < 0)
1263 return err;
1264
Andrew Lunn34386342017-07-30 22:41:45 +02001265 return genphy_soft_reset(phydev);
Ron Madrid605f1962008-11-06 09:05:26 +00001266}
1267
David Daney90600732010-11-19 11:58:53 +00001268static int m88e1149_config_init(struct phy_device *phydev)
1269{
1270 int err;
1271
1272 /* Change address */
Andrew Lunn52295662017-05-25 21:42:08 +02001273 err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
David Daney90600732010-11-19 11:58:53 +00001274 if (err < 0)
1275 return err;
1276
1277 /* Enable 1000 Mbit */
1278 err = phy_write(phydev, 0x15, 0x1048);
1279 if (err < 0)
1280 return err;
1281
David Daneycf41a512010-11-19 12:13:18 +00001282 err = marvell_of_reg_init(phydev);
1283 if (err < 0)
1284 return err;
1285
David Daney90600732010-11-19 11:58:53 +00001286 /* Reset address */
Andrew Lunn52295662017-05-25 21:42:08 +02001287 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
David Daney90600732010-11-19 11:58:53 +00001288 if (err < 0)
1289 return err;
1290
Andrew Lunn34386342017-07-30 22:41:45 +02001291 return genphy_soft_reset(phydev);
David Daney90600732010-11-19 11:58:53 +00001292}
1293
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001294static int m88e1145_config_init_rgmii(struct phy_device *phydev)
1295{
1296 int err;
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001297
Andrew Lunn61111592017-07-30 22:41:46 +02001298 err = m88e1111_config_init_rgmii_delays(phydev);
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001299 if (err < 0)
1300 return err;
1301
1302 if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
1303 err = phy_write(phydev, 0x1d, 0x0012);
1304 if (err < 0)
1305 return err;
1306
Russell Kingf1028522018-01-05 16:07:10 +00001307 err = phy_modify(phydev, 0x1e, 0x0fc0,
Russell Kingfea23fb2018-01-02 10:58:58 +00001308 2 << 9 | /* 36 ohm */
1309 2 << 6); /* 39 ohm */
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001310 if (err < 0)
1311 return err;
1312
1313 err = phy_write(phydev, 0x1d, 0x3);
1314 if (err < 0)
1315 return err;
1316
1317 err = phy_write(phydev, 0x1e, 0x8000);
1318 }
1319 return err;
1320}
1321
1322static int m88e1145_config_init_sgmii(struct phy_device *phydev)
1323{
Andrew Lunn865b813a2017-07-30 22:41:47 +02001324 return m88e1111_config_init_hwcfg_mode(
1325 phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
1326 MII_M1111_HWCFG_FIBER_COPPER_AUTO);
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001327}
1328
Andy Fleming76884672007-02-09 18:13:58 -06001329static int m88e1145_config_init(struct phy_device *phydev)
1330{
1331 int err;
1332
1333 /* Take care of errata E0 & E1 */
1334 err = phy_write(phydev, 0x1d, 0x001b);
1335 if (err < 0)
1336 return err;
1337
1338 err = phy_write(phydev, 0x1e, 0x418f);
1339 if (err < 0)
1340 return err;
1341
1342 err = phy_write(phydev, 0x1d, 0x0016);
1343 if (err < 0)
1344 return err;
1345
1346 err = phy_write(phydev, 0x1e, 0xa2da);
1347 if (err < 0)
1348 return err;
1349
Kim Phillips895ee682007-06-05 18:46:47 +08001350 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001351 err = m88e1145_config_init_rgmii(phydev);
Andy Fleming76884672007-02-09 18:13:58 -06001352 if (err < 0)
1353 return err;
Andy Fleming76884672007-02-09 18:13:58 -06001354 }
1355
Viet Nga Daob0224172014-10-23 19:41:53 -07001356 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001357 err = m88e1145_config_init_sgmii(phydev);
Viet Nga Daob0224172014-10-23 19:41:53 -07001358 if (err < 0)
1359 return err;
1360 }
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03001361 err = m88e1111_set_downshift(phydev, 3);
1362 if (err < 0)
1363 return err;
Viet Nga Daob0224172014-10-23 19:41:53 -07001364
David Daneycf41a512010-11-19 12:13:18 +00001365 err = marvell_of_reg_init(phydev);
1366 if (err < 0)
1367 return err;
1368
Andy Fleming76884672007-02-09 18:13:58 -06001369 return 0;
1370}
Andy Fleming00db8182005-07-30 19:31:23 -04001371
Heiner Kallweit69f42be2019-03-25 19:35:41 +01001372static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)
1373{
1374 int val;
1375
1376 val = phy_read(phydev, MII_88E1540_COPPER_CTRL3);
1377 if (val < 0)
1378 return val;
1379
1380 if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) {
1381 *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
1382 return 0;
1383 }
1384
1385 val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
1386
1387 switch (val) {
1388 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS:
1389 *msecs = 0;
1390 break;
1391 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS:
1392 *msecs = 10;
1393 break;
1394 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS:
1395 *msecs = 20;
1396 break;
1397 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS:
1398 *msecs = 40;
1399 break;
1400 default:
1401 return -EINVAL;
1402 }
1403
1404 return 0;
1405}
1406
1407static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)
1408{
1409 struct ethtool_eee eee;
1410 int val, ret;
1411
1412 if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
1413 return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3,
1414 MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
1415
1416 /* According to the Marvell data sheet EEE must be disabled for
1417 * Fast Link Down detection to work properly
1418 */
1419 ret = phy_ethtool_get_eee(phydev, &eee);
1420 if (!ret && eee.eee_enabled) {
1421 phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");
1422 return -EBUSY;
1423 }
1424
1425 if (*msecs <= 5)
1426 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS;
1427 else if (*msecs <= 15)
1428 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS;
1429 else if (*msecs <= 30)
1430 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS;
1431 else
1432 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS;
1433
1434 val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
1435
1436 ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3,
1437 MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
1438 if (ret)
1439 return ret;
1440
1441 return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3,
1442 MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
1443}
1444
1445static int m88e1540_get_tunable(struct phy_device *phydev,
1446 struct ethtool_tunable *tuna, void *data)
1447{
1448 switch (tuna->id) {
1449 case ETHTOOL_PHY_FAST_LINK_DOWN:
1450 return m88e1540_get_fld(phydev, data);
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001451 case ETHTOOL_PHY_DOWNSHIFT:
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001452 return m88e1011_get_downshift(phydev, data);
Heiner Kallweit69f42be2019-03-25 19:35:41 +01001453 default:
1454 return -EOPNOTSUPP;
1455 }
1456}
1457
1458static int m88e1540_set_tunable(struct phy_device *phydev,
1459 struct ethtool_tunable *tuna, const void *data)
1460{
1461 switch (tuna->id) {
1462 case ETHTOOL_PHY_FAST_LINK_DOWN:
1463 return m88e1540_set_fld(phydev, data);
Heiner Kallweita3bdfce2019-10-19 15:57:33 +02001464 case ETHTOOL_PHY_DOWNSHIFT:
Heiner Kallweit911af5e2019-10-28 20:52:55 +01001465 return m88e1011_set_downshift(phydev, *(const u8 *)data);
Heiner Kallweit69f42be2019-03-25 19:35:41 +01001466 default:
1467 return -EOPNOTSUPP;
1468 }
1469}
1470
Andrew Lunn8cbcdc12019-01-10 22:48:36 +01001471/* The VOD can be out of specification on link up. Poke an
1472 * undocumented register, in an undocumented page, with a magic value
1473 * to fix this.
1474 */
1475static int m88e6390_errata(struct phy_device *phydev)
1476{
1477 int err;
1478
1479 err = phy_write(phydev, MII_BMCR,
1480 BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX);
1481 if (err)
1482 return err;
1483
1484 usleep_range(300, 400);
1485
1486 err = phy_write_paged(phydev, 0xf8, 0x08, 0x36);
1487 if (err)
1488 return err;
1489
1490 return genphy_soft_reset(phydev);
1491}
1492
1493static int m88e6390_config_aneg(struct phy_device *phydev)
1494{
1495 int err;
1496
1497 err = m88e6390_errata(phydev);
1498 if (err)
1499 return err;
1500
1501 return m88e1510_config_aneg(phydev);
1502}
1503
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001504/**
Andrew Lunnab9cb722018-12-05 21:49:42 +01001505 * fiber_lpa_mod_linkmode_lpa_t
Andrew Lunnc0ec3c22018-11-10 23:43:34 +01001506 * @advertising: the linkmode advertisement settings
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001507 * @lpa: value of the MII_LPA register for fiber link
Alexandr Smirnovbe937f12008-03-19 00:37:24 +03001508 *
Andrew Lunnab9cb722018-12-05 21:49:42 +01001509 * A small helper function that translates MII_LPA bits to linkmode LP
1510 * advertisement settings. Other bits in advertising are left
1511 * unchanged.
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001512 */
Andrew Lunnab9cb722018-12-05 21:49:42 +01001513static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa)
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001514{
Andrew Lunnab9cb722018-12-05 21:49:42 +01001515 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
Russell King20ecf422019-12-17 13:39:42 +00001516 advertising, lpa & LPA_1000XHALF);
Andrew Lunnab9cb722018-12-05 21:49:42 +01001517
1518 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
Russell King20ecf422019-12-17 13:39:42 +00001519 advertising, lpa & LPA_1000XFULL);
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001520}
1521
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001522static int marvell_read_status_page_an(struct phy_device *phydev,
Russell Kingd2004e22019-12-17 13:39:36 +00001523 int fiber, int status)
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001524{
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001525 int lpa;
Russell Kingfcf1f592019-12-17 13:39:21 +00001526 int err;
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001527
Clemens Gruber3b72f842020-04-11 18:51:25 +02001528 if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) {
1529 phydev->link = 0;
1530 return 0;
1531 }
1532
1533 if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
1534 phydev->duplex = DUPLEX_FULL;
1535 else
1536 phydev->duplex = DUPLEX_HALF;
1537
1538 switch (status & MII_M1011_PHY_STATUS_SPD_MASK) {
1539 case MII_M1011_PHY_STATUS_1000:
1540 phydev->speed = SPEED_1000;
1541 break;
1542
1543 case MII_M1011_PHY_STATUS_100:
1544 phydev->speed = SPEED_100;
1545 break;
1546
1547 default:
1548 phydev->speed = SPEED_10;
1549 break;
1550 }
1551
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001552 if (!fiber) {
Russell Kingfcf1f592019-12-17 13:39:21 +00001553 err = genphy_read_lpa(phydev);
1554 if (err < 0)
1555 return err;
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001556
Russell Kingaf006242019-12-17 13:39:06 +00001557 phy_resolve_aneg_pause(phydev);
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001558 } else {
Russell Kingfcf1f592019-12-17 13:39:21 +00001559 lpa = phy_read(phydev, MII_LPA);
1560 if (lpa < 0)
1561 return lpa;
1562
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001563 /* The fiber link is only 1000M capable */
Andrew Lunnab9cb722018-12-05 21:49:42 +01001564 fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001565
1566 if (phydev->duplex == DUPLEX_FULL) {
1567 if (!(lpa & LPA_PAUSE_FIBER)) {
1568 phydev->pause = 0;
1569 phydev->asym_pause = 0;
1570 } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) {
1571 phydev->pause = 1;
1572 phydev->asym_pause = 1;
1573 } else {
1574 phydev->pause = 1;
1575 phydev->asym_pause = 0;
1576 }
1577 }
1578 }
Russell Kingfcf1f592019-12-17 13:39:21 +00001579
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001580 return 0;
1581}
1582
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001583/* marvell_read_status_page
1584 *
Jeff Garzikf0c88f92008-03-25 23:53:24 -04001585 * Description:
Alexandr Smirnovbe937f12008-03-19 00:37:24 +03001586 * Check the link, then figure out the current state
1587 * by comparing what we advertise with what the link partner
1588 * advertises. Start by checking the gigabit possibilities,
1589 * then move on to 10/100.
1590 */
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001591static int marvell_read_status_page(struct phy_device *phydev, int page)
Alexandr Smirnovbe937f12008-03-19 00:37:24 +03001592{
Russell Kingd2004e22019-12-17 13:39:36 +00001593 int status;
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001594 int fiber;
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001595 int err;
Alexandr Smirnovbe937f12008-03-19 00:37:24 +03001596
Russell Kingd2004e22019-12-17 13:39:36 +00001597 status = phy_read(phydev, MII_M1011_PHY_STATUS);
1598 if (status < 0)
1599 return status;
1600
1601 /* Use the generic register for copper link status,
1602 * and the PHY status register for fiber link status.
Andrew Lunn0c3439b2017-05-17 03:25:59 +02001603 */
Russell Kingd2004e22019-12-17 13:39:36 +00001604 if (page == MII_MARVELL_FIBER_PAGE) {
1605 phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK);
1606 } else {
1607 err = genphy_update_link(phydev);
1608 if (err)
1609 return err;
1610 }
1611
Andrew Lunn52295662017-05-25 21:42:08 +02001612 if (page == MII_MARVELL_FIBER_PAGE)
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001613 fiber = 1;
1614 else
1615 fiber = 0;
1616
Russell King98f92832019-12-17 13:39:26 +00001617 linkmode_zero(phydev->lp_advertising);
1618 phydev->pause = 0;
1619 phydev->asym_pause = 0;
Russell Kingb82cf172020-02-27 09:44:49 +00001620 phydev->speed = SPEED_UNKNOWN;
1621 phydev->duplex = DUPLEX_UNKNOWN;
Michael Walle4217a642021-02-09 17:38:52 +01001622 phydev->port = fiber ? PORT_FIBRE : PORT_TP;
Russell King98f92832019-12-17 13:39:26 +00001623
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001624 if (phydev->autoneg == AUTONEG_ENABLE)
Russell Kingd2004e22019-12-17 13:39:36 +00001625 err = marvell_read_status_page_an(phydev, fiber, status);
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001626 else
Russell King98f92832019-12-17 13:39:26 +00001627 err = genphy_read_status_fixed(phydev);
Alexandr Smirnovbe937f12008-03-19 00:37:24 +03001628
Andrew Lunne1dde8d2017-05-17 03:26:02 +02001629 return err;
Alexandr Smirnovbe937f12008-03-19 00:37:24 +03001630}
1631
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001632/* marvell_read_status
1633 *
1634 * Some Marvell's phys have two modes: fiber and copper.
1635 * Both need status checked.
1636 * Description:
1637 * First, check the fiber link and status.
1638 * If the fiber link is down, check the copper link and status which
1639 * will be the default value if both link are down.
1640 */
1641static int marvell_read_status(struct phy_device *phydev)
1642{
1643 int err;
1644
1645 /* Check the fiber mode first */
Andrew Lunn3c1bcc82018-11-10 23:43:33 +01001646 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1647 phydev->supported) &&
Russell Kinga13c06522017-01-10 23:13:45 +00001648 phydev->interface != PHY_INTERFACE_MODE_SGMII) {
Andrew Lunn52295662017-05-25 21:42:08 +02001649 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001650 if (err < 0)
1651 goto error;
1652
Andrew Lunn52295662017-05-25 21:42:08 +02001653 err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE);
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001654 if (err < 0)
1655 goto error;
1656
Andrew Lunn0c3439b2017-05-17 03:25:59 +02001657 /* If the fiber link is up, it is the selected and
1658 * used link. In this case, we need to stay in the
1659 * fiber page. Please to be careful about that, avoid
1660 * to restore Copper page in other functions which
1661 * could break the behaviour for some fiber phy like
1662 * 88E1512.
1663 */
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001664 if (phydev->link)
1665 return 0;
1666
1667 /* If fiber link is down, check and save copper mode state */
Andrew Lunn52295662017-05-25 21:42:08 +02001668 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001669 if (err < 0)
1670 goto error;
1671 }
1672
Andrew Lunn52295662017-05-25 21:42:08 +02001673 return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001674
1675error:
Andrew Lunn52295662017-05-25 21:42:08 +02001676 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret6cfb3bc2016-07-19 11:13:10 +02001677 return err;
1678}
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001679
1680/* marvell_suspend
1681 *
1682 * Some Marvell's phys have two modes: fiber and copper.
1683 * Both need to be suspended
1684 */
1685static int marvell_suspend(struct phy_device *phydev)
1686{
1687 int err;
1688
1689 /* Suspend the fiber mode first */
Andrew Lunn3c1bcc82018-11-10 23:43:33 +01001690 if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1691 phydev->supported)) {
Andrew Lunn52295662017-05-25 21:42:08 +02001692 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001693 if (err < 0)
1694 goto error;
1695
1696 /* With the page set, use the generic suspend */
1697 err = genphy_suspend(phydev);
1698 if (err < 0)
1699 goto error;
1700
1701 /* Then, the copper link */
Andrew Lunn52295662017-05-25 21:42:08 +02001702 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001703 if (err < 0)
1704 goto error;
1705 }
1706
1707 /* With the page set, use the generic suspend */
1708 return genphy_suspend(phydev);
1709
1710error:
Andrew Lunn52295662017-05-25 21:42:08 +02001711 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001712 return err;
1713}
1714
1715/* marvell_resume
1716 *
1717 * Some Marvell's phys have two modes: fiber and copper.
1718 * Both need to be resumed
1719 */
1720static int marvell_resume(struct phy_device *phydev)
1721{
1722 int err;
1723
1724 /* Resume the fiber mode first */
Andrew Lunn3c1bcc82018-11-10 23:43:33 +01001725 if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1726 phydev->supported)) {
Andrew Lunn52295662017-05-25 21:42:08 +02001727 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001728 if (err < 0)
1729 goto error;
1730
1731 /* With the page set, use the generic resume */
1732 err = genphy_resume(phydev);
1733 if (err < 0)
1734 goto error;
1735
1736 /* Then, the copper link */
Andrew Lunn52295662017-05-25 21:42:08 +02001737 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001738 if (err < 0)
1739 goto error;
1740 }
1741
1742 /* With the page set, use the generic resume */
1743 return genphy_resume(phydev);
1744
1745error:
Andrew Lunn52295662017-05-25 21:42:08 +02001746 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
Charles-Antoine Couret3758be32016-07-19 11:13:13 +02001747 return err;
1748}
1749
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +02001750static int marvell_aneg_done(struct phy_device *phydev)
1751{
1752 int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
Andrew Lunne69d9ed2017-05-17 03:26:00 +02001753
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +02001754 return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
1755}
1756
Andrew Lunn23beb382017-05-17 03:26:04 +02001757static void m88e1318_get_wol(struct phy_device *phydev,
1758 struct ethtool_wolinfo *wol)
Michael Stapelberg3871c382013-03-11 13:56:45 +00001759{
Jisheng Zhangf4f9dcc2020-10-05 17:19:50 +08001760 int ret;
Russell King424ca4c2018-01-02 10:58:48 +00001761
Song Yoong Siang61646592021-08-13 16:45:08 +08001762 wol->supported = WAKE_MAGIC | WAKE_PHY;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001763 wol->wolopts = 0;
1764
Jisheng Zhangf4f9dcc2020-10-05 17:19:50 +08001765 ret = phy_read_paged(phydev, MII_MARVELL_WOL_PAGE,
1766 MII_88E1318S_PHY_WOL_CTRL);
Song Yoong Siang61646592021-08-13 16:45:08 +08001767 if (ret < 0)
1768 return;
1769
1770 if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
Michael Stapelberg3871c382013-03-11 13:56:45 +00001771 wol->wolopts |= WAKE_MAGIC;
Song Yoong Siang61646592021-08-13 16:45:08 +08001772
1773 if (ret & MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE)
1774 wol->wolopts |= WAKE_PHY;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001775}
1776
Andrew Lunn23beb382017-05-17 03:26:04 +02001777static int m88e1318_set_wol(struct phy_device *phydev,
1778 struct ethtool_wolinfo *wol)
Michael Stapelberg3871c382013-03-11 13:56:45 +00001779{
Russell King424ca4c2018-01-02 10:58:48 +00001780 int err = 0, oldpage;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001781
Russell King424ca4c2018-01-02 10:58:48 +00001782 oldpage = phy_save_page(phydev);
1783 if (oldpage < 0)
1784 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001785
Song Yoong Siang61646592021-08-13 16:45:08 +08001786 if (wol->wolopts & (WAKE_MAGIC | WAKE_PHY)) {
Michael Stapelberg3871c382013-03-11 13:56:45 +00001787 /* Explicitly switch to page 0x00, just to be sure */
Russell King424ca4c2018-01-02 10:58:48 +00001788 err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001789 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001790 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001791
Jingju Houb6a930f2018-04-23 15:22:49 +08001792 /* If WOL event happened once, the LED[2] interrupt pin
1793 * will not be cleared unless we reading the interrupt status
1794 * register. If interrupts are in use, the normal interrupt
1795 * handling will clear the WOL event. Clear the WOL event
1796 * before enabling it if !phy_interrupt_is_valid()
1797 */
1798 if (!phy_interrupt_is_valid(phydev))
Andrew Lunne0a73282019-01-11 00:15:21 +01001799 __phy_read(phydev, MII_M1011_IEVENT);
Jingju Houb6a930f2018-04-23 15:22:49 +08001800
Michael Stapelberg3871c382013-03-11 13:56:45 +00001801 /* Enable the WOL interrupt */
Yejune Deng832913c2020-11-30 18:41:35 +08001802 err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER,
1803 MII_88E1318S_PHY_CSIER_WOL_EIE);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001804 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001805 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001806
Russell King424ca4c2018-01-02 10:58:48 +00001807 err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001808 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001809 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001810
1811 /* Setup LED[2] as interrupt pin (active low) */
Russell King424ca4c2018-01-02 10:58:48 +00001812 err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR,
Russell Kingf1028522018-01-05 16:07:10 +00001813 MII_88E1318S_PHY_LED_TCR_FORCE_INT,
Russell King424ca4c2018-01-02 10:58:48 +00001814 MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
1815 MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001816 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001817 goto error;
Song Yoong Siang61646592021-08-13 16:45:08 +08001818 }
Michael Stapelberg3871c382013-03-11 13:56:45 +00001819
Song Yoong Siang61646592021-08-13 16:45:08 +08001820 if (wol->wolopts & WAKE_MAGIC) {
Russell King424ca4c2018-01-02 10:58:48 +00001821 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001822 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001823 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001824
1825 /* Store the device address for the magic packet */
Russell King424ca4c2018-01-02 10:58:48 +00001826 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
Michael Stapelberg3871c382013-03-11 13:56:45 +00001827 ((phydev->attached_dev->dev_addr[5] << 8) |
1828 phydev->attached_dev->dev_addr[4]));
1829 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001830 goto error;
1831 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
Michael Stapelberg3871c382013-03-11 13:56:45 +00001832 ((phydev->attached_dev->dev_addr[3] << 8) |
1833 phydev->attached_dev->dev_addr[2]));
1834 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001835 goto error;
1836 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
Michael Stapelberg3871c382013-03-11 13:56:45 +00001837 ((phydev->attached_dev->dev_addr[1] << 8) |
1838 phydev->attached_dev->dev_addr[0]));
1839 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001840 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001841
1842 /* Clear WOL status and enable magic packet matching */
Yejune Deng832913c2020-11-30 18:41:35 +08001843 err = __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL,
1844 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |
1845 MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001846 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001847 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001848 } else {
Russell King424ca4c2018-01-02 10:58:48 +00001849 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001850 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001851 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001852
1853 /* Clear WOL status and disable magic packet matching */
Russell King424ca4c2018-01-02 10:58:48 +00001854 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,
Russell Kingf1028522018-01-05 16:07:10 +00001855 MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE,
Russell King424ca4c2018-01-02 10:58:48 +00001856 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001857 if (err < 0)
Russell King424ca4c2018-01-02 10:58:48 +00001858 goto error;
Michael Stapelberg3871c382013-03-11 13:56:45 +00001859 }
1860
Song Yoong Siang61646592021-08-13 16:45:08 +08001861 if (wol->wolopts & WAKE_PHY) {
1862 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
1863 if (err < 0)
1864 goto error;
1865
1866 /* Clear WOL status and enable link up event */
1867 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0,
1868 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |
1869 MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE);
1870 if (err < 0)
1871 goto error;
1872 } else {
1873 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
1874 if (err < 0)
1875 goto error;
1876
1877 /* Clear WOL status and disable link up event */
1878 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,
1879 MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE,
1880 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);
1881 if (err < 0)
1882 goto error;
1883 }
1884
Russell King424ca4c2018-01-02 10:58:48 +00001885error:
1886 return phy_restore_page(phydev, oldpage, err);
Michael Stapelberg3871c382013-03-11 13:56:45 +00001887}
1888
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001889static int marvell_get_sset_count(struct phy_device *phydev)
1890{
Andrew Lunn3c1bcc82018-11-10 23:43:33 +01001891 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
1892 phydev->supported))
Charles-Antoine Couret2170fef2016-07-19 11:13:11 +02001893 return ARRAY_SIZE(marvell_hw_stats);
1894 else
1895 return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001896}
1897
1898static void marvell_get_strings(struct phy_device *phydev, u8 *data)
1899{
Andrew Lunnfdfdf862019-04-25 00:33:00 +02001900 int count = marvell_get_sset_count(phydev);
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001901 int i;
1902
Andrew Lunnfdfdf862019-04-25 00:33:00 +02001903 for (i = 0; i < count; i++) {
Florian Fainelli98409b22018-03-02 15:08:37 -08001904 strlcpy(data + i * ETH_GSTRING_LEN,
1905 marvell_hw_stats[i].string, ETH_GSTRING_LEN);
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001906 }
1907}
1908
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001909static u64 marvell_get_stat(struct phy_device *phydev, int i)
1910{
1911 struct marvell_hw_stat stat = marvell_hw_stats[i];
1912 struct marvell_priv *priv = phydev->priv;
Russell King424ca4c2018-01-02 10:58:48 +00001913 int val;
Andrew Lunn321b4d42016-02-20 00:35:29 +01001914 u64 ret;
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001915
Russell King424ca4c2018-01-02 10:58:48 +00001916 val = phy_read_paged(phydev, stat.page, stat.reg);
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001917 if (val < 0) {
Jisheng Zhang6c3442f2018-04-27 16:18:58 +08001918 ret = U64_MAX;
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001919 } else {
1920 val = val & ((1 << stat.bits) - 1);
1921 priv->stats[i] += val;
Andrew Lunn321b4d42016-02-20 00:35:29 +01001922 ret = priv->stats[i];
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001923 }
1924
Andrew Lunn321b4d42016-02-20 00:35:29 +01001925 return ret;
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001926}
1927
1928static void marvell_get_stats(struct phy_device *phydev,
1929 struct ethtool_stats *stats, u64 *data)
1930{
Andrew Lunnfdfdf862019-04-25 00:33:00 +02001931 int count = marvell_get_sset_count(phydev);
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001932 int i;
1933
Andrew Lunnfdfdf862019-04-25 00:33:00 +02001934 for (i = 0; i < count; i++)
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01001935 data[i] = marvell_get_stat(phydev, i);
1936}
1937
Mohammad Athari Bin Ismail020a45a2022-01-15 17:25:15 +08001938static int m88e1510_loopback(struct phy_device *phydev, bool enable)
1939{
1940 int err;
1941
1942 if (enable) {
1943 u16 bmcr_ctl = 0, mscr2_ctl = 0;
1944
1945 if (phydev->speed == SPEED_1000)
1946 bmcr_ctl = BMCR_SPEED1000;
1947 else if (phydev->speed == SPEED_100)
1948 bmcr_ctl = BMCR_SPEED100;
1949
1950 if (phydev->duplex == DUPLEX_FULL)
1951 bmcr_ctl |= BMCR_FULLDPLX;
1952
1953 err = phy_write(phydev, MII_BMCR, bmcr_ctl);
1954 if (err < 0)
1955 return err;
1956
1957 if (phydev->speed == SPEED_1000)
1958 mscr2_ctl = BMCR_SPEED1000;
1959 else if (phydev->speed == SPEED_100)
1960 mscr2_ctl = BMCR_SPEED100;
1961
1962 err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
1963 MII_88E1510_MSCR_2, BMCR_SPEED1000 |
1964 BMCR_SPEED100, mscr2_ctl);
1965 if (err < 0)
1966 return err;
1967
1968 /* Need soft reset to have speed configuration takes effect */
1969 err = genphy_soft_reset(phydev);
1970 if (err < 0)
1971 return err;
1972
1973 /* FIXME: Based on trial and error test, it seem 1G need to have
1974 * delay between soft reset and loopback enablement.
1975 */
1976 if (phydev->speed == SPEED_1000)
1977 msleep(1000);
1978
1979 return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
1980 BMCR_LOOPBACK);
1981 } else {
1982 err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);
1983 if (err < 0)
1984 return err;
1985
1986 return phy_config_aneg(phydev);
1987 }
1988}
1989
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02001990static int marvell_vct5_wait_complete(struct phy_device *phydev)
1991{
1992 int i;
1993 int val;
1994
1995 for (i = 0; i < 32; i++) {
Andrew Lunna618e86d2020-05-27 00:21:42 +02001996 val = __phy_read(phydev, MII_VCT5_CTRL);
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02001997 if (val < 0)
1998 return val;
1999
2000 if (val & MII_VCT5_CTRL_COMPLETE)
2001 return 0;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002002 }
2003
2004 phydev_err(phydev, "Timeout while waiting for cable test to finish\n");
2005 return -ETIMEDOUT;
2006}
2007
2008static int marvell_vct5_amplitude(struct phy_device *phydev, int pair)
2009{
2010 int amplitude;
2011 int val;
2012 int reg;
2013
2014 reg = MII_VCT5_TX_RX_MDI0_COUPLING + pair;
Andrew Lunna618e86d2020-05-27 00:21:42 +02002015 val = __phy_read(phydev, reg);
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002016
2017 if (val < 0)
2018 return 0;
2019
2020 amplitude = (val & MII_VCT5_TX_RX_AMPLITUDE_MASK) >>
2021 MII_VCT5_TX_RX_AMPLITUDE_SHIFT;
2022
2023 if (!(val & MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION))
2024 amplitude = -amplitude;
2025
2026 return 1000 * amplitude / 128;
2027}
2028
2029static u32 marvell_vct5_distance2cm(int distance)
2030{
2031 return distance * 805 / 10;
2032}
2033
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002034static u32 marvell_vct5_cm2distance(int cm)
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002035{
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002036 return cm * 10 / 805;
2037}
2038
2039static int marvell_vct5_amplitude_distance(struct phy_device *phydev,
2040 int distance, int pair)
2041{
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002042 u16 reg;
2043 int err;
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002044 int mV;
2045 int i;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002046
Andrew Lunna618e86d2020-05-27 00:21:42 +02002047 err = __phy_write(phydev, MII_VCT5_SAMPLE_POINT_DISTANCE,
2048 distance);
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002049 if (err)
2050 return err;
2051
2052 reg = MII_VCT5_CTRL_ENABLE |
2053 MII_VCT5_CTRL_TX_SAME_CHANNEL |
2054 MII_VCT5_CTRL_SAMPLES_DEFAULT |
2055 MII_VCT5_CTRL_SAMPLE_POINT |
2056 MII_VCT5_CTRL_PEEK_HYST_DEFAULT;
Andrew Lunna618e86d2020-05-27 00:21:42 +02002057 err = __phy_write(phydev, MII_VCT5_CTRL, reg);
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002058 if (err)
2059 return err;
2060
2061 err = marvell_vct5_wait_complete(phydev);
2062 if (err)
2063 return err;
2064
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002065 for (i = 0; i < 4; i++) {
2066 if (pair != PHY_PAIR_ALL && i != pair)
2067 continue;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002068
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002069 mV = marvell_vct5_amplitude(phydev, i);
2070 ethnl_cable_test_amplitude(phydev, i, mV);
2071 }
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002072
2073 return 0;
2074}
2075
2076static int marvell_vct5_amplitude_graph(struct phy_device *phydev)
2077{
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002078 struct marvell_priv *priv = phydev->priv;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002079 int distance;
Andrew Lunndb8668a2020-05-27 00:21:43 +02002080 u16 width;
Andrew Lunna618e86d2020-05-27 00:21:42 +02002081 int page;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002082 int err;
2083 u16 reg;
2084
Andrew Lunndb8668a2020-05-27 00:21:43 +02002085 if (priv->first <= TDR_SHORT_CABLE_LENGTH)
2086 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS;
2087 else
2088 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;
2089
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002090 reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |
2091 MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |
Andrew Lunndb8668a2020-05-27 00:21:43 +02002092 MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002093
2094 err = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,
2095 MII_VCT5_TX_PULSE_CTRL, reg);
2096 if (err)
2097 return err;
2098
Andrew Lunna618e86d2020-05-27 00:21:42 +02002099 /* Reading the TDR data is very MDIO heavy. We need to optimize
2100 * access to keep the time to a minimum. So lock the bus once,
2101 * and don't release it until complete. We can then avoid having
2102 * to change the page for every access, greatly speeding things
2103 * up.
2104 */
2105 page = phy_select_page(phydev, MII_MARVELL_VCT5_PAGE);
2106 if (page < 0)
Dan Carpenter830f5ce2020-05-29 13:02:07 +03002107 goto restore_page;
Andrew Lunna618e86d2020-05-27 00:21:42 +02002108
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002109 for (distance = priv->first;
2110 distance <= priv->last;
2111 distance += priv->step) {
2112 err = marvell_vct5_amplitude_distance(phydev, distance,
2113 priv->pair);
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002114 if (err)
Andrew Lunna618e86d2020-05-27 00:21:42 +02002115 goto restore_page;
Andrew Lunndb8668a2020-05-27 00:21:43 +02002116
2117 if (distance > TDR_SHORT_CABLE_LENGTH &&
2118 width == MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS) {
2119 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;
2120 reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |
2121 MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |
2122 MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;
2123 err = __phy_write(phydev, MII_VCT5_TX_PULSE_CTRL, reg);
2124 if (err)
2125 goto restore_page;
2126 }
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002127 }
2128
Andrew Lunna618e86d2020-05-27 00:21:42 +02002129restore_page:
2130 return phy_restore_page(phydev, page, err);
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002131}
2132
2133static int marvell_cable_test_start_common(struct phy_device *phydev)
Andrew Lunnfc879f72020-05-10 21:12:38 +02002134{
2135 int bmcr, bmsr, ret;
2136
2137 /* If auto-negotiation is enabled, but not complete, the cable
2138 * test never completes. So disable auto-neg.
2139 */
2140 bmcr = phy_read(phydev, MII_BMCR);
2141 if (bmcr < 0)
2142 return bmcr;
2143
2144 bmsr = phy_read(phydev, MII_BMSR);
2145
2146 if (bmsr < 0)
2147 return bmsr;
2148
2149 if (bmcr & BMCR_ANENABLE) {
Yejune Deng832913c2020-11-30 18:41:35 +08002150 ret = phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE);
Andrew Lunnfc879f72020-05-10 21:12:38 +02002151 if (ret < 0)
2152 return ret;
2153 ret = genphy_soft_reset(phydev);
2154 if (ret < 0)
2155 return ret;
2156 }
2157
2158 /* If the link is up, allow it some time to go down */
2159 if (bmsr & BMSR_LSTATUS)
2160 msleep(1500);
2161
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002162 return 0;
2163}
2164
2165static int marvell_vct7_cable_test_start(struct phy_device *phydev)
2166{
2167 struct marvell_priv *priv = phydev->priv;
2168 int ret;
2169
2170 ret = marvell_cable_test_start_common(phydev);
2171 if (ret)
2172 return ret;
2173
2174 priv->cable_test_tdr = false;
2175
2176 /* Reset the VCT5 API control to defaults, otherwise
2177 * VCT7 does not work correctly.
2178 */
2179 ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,
2180 MII_VCT5_CTRL,
2181 MII_VCT5_CTRL_TX_SAME_CHANNEL |
2182 MII_VCT5_CTRL_SAMPLES_DEFAULT |
2183 MII_VCT5_CTRL_MODE_MAXIMUM_PEEK |
2184 MII_VCT5_CTRL_PEEK_HYST_DEFAULT);
2185 if (ret)
2186 return ret;
2187
2188 ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,
2189 MII_VCT5_SAMPLE_POINT_DISTANCE, 0);
2190 if (ret)
2191 return ret;
2192
Andrew Lunnfc879f72020-05-10 21:12:38 +02002193 return phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,
2194 MII_VCT7_CTRL,
2195 MII_VCT7_CTRL_RUN_NOW |
2196 MII_VCT7_CTRL_CENTIMETERS);
2197}
2198
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002199static int marvell_vct5_cable_test_tdr_start(struct phy_device *phydev,
2200 const struct phy_tdr_config *cfg)
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002201{
2202 struct marvell_priv *priv = phydev->priv;
2203 int ret;
2204
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002205 priv->cable_test_tdr = true;
2206 priv->first = marvell_vct5_cm2distance(cfg->first);
2207 priv->last = marvell_vct5_cm2distance(cfg->last);
2208 priv->step = marvell_vct5_cm2distance(cfg->step);
2209 priv->pair = cfg->pair;
2210
2211 if (priv->first > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)
2212 return -EINVAL;
2213
2214 if (priv->last > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)
2215 return -EINVAL;
2216
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002217 /* Disable VCT7 */
2218 ret = phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,
2219 MII_VCT7_CTRL, 0);
2220 if (ret)
2221 return ret;
2222
2223 ret = marvell_cable_test_start_common(phydev);
2224 if (ret)
2225 return ret;
2226
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002227 ret = ethnl_cable_test_pulse(phydev, 1000);
2228 if (ret)
2229 return ret;
2230
2231 return ethnl_cable_test_step(phydev,
Andrew Lunnf2bc8ad2020-05-27 00:21:41 +02002232 marvell_vct5_distance2cm(priv->first),
2233 marvell_vct5_distance2cm(priv->last),
2234 marvell_vct5_distance2cm(priv->step));
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002235}
2236
Andrew Lunnfc879f72020-05-10 21:12:38 +02002237static int marvell_vct7_distance_to_length(int distance, bool meter)
2238{
2239 if (meter)
2240 distance *= 100;
2241
2242 return distance;
2243}
2244
2245static bool marvell_vct7_distance_valid(int result)
2246{
2247 switch (result) {
2248 case MII_VCT7_RESULTS_OPEN:
2249 case MII_VCT7_RESULTS_SAME_SHORT:
2250 case MII_VCT7_RESULTS_CROSS_SHORT:
2251 return true;
2252 }
2253 return false;
2254}
2255
2256static int marvell_vct7_report_length(struct phy_device *phydev,
2257 int pair, bool meter)
2258{
2259 int length;
2260 int ret;
2261
2262 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,
2263 MII_VCT7_PAIR_0_DISTANCE + pair);
2264 if (ret < 0)
2265 return ret;
2266
2267 length = marvell_vct7_distance_to_length(ret, meter);
2268
2269 ethnl_cable_test_fault_length(phydev, pair, length);
2270
2271 return 0;
2272}
2273
2274static int marvell_vct7_cable_test_report_trans(int result)
2275{
2276 switch (result) {
2277 case MII_VCT7_RESULTS_OK:
2278 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
2279 case MII_VCT7_RESULTS_OPEN:
2280 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
2281 case MII_VCT7_RESULTS_SAME_SHORT:
2282 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
2283 case MII_VCT7_RESULTS_CROSS_SHORT:
2284 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
2285 default:
2286 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
2287 }
2288}
2289
2290static int marvell_vct7_cable_test_report(struct phy_device *phydev)
2291{
2292 int pair0, pair1, pair2, pair3;
2293 bool meter;
2294 int ret;
2295
2296 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,
2297 MII_VCT7_RESULTS);
2298 if (ret < 0)
2299 return ret;
2300
2301 pair3 = (ret & MII_VCT7_RESULTS_PAIR3_MASK) >>
2302 MII_VCT7_RESULTS_PAIR3_SHIFT;
2303 pair2 = (ret & MII_VCT7_RESULTS_PAIR2_MASK) >>
2304 MII_VCT7_RESULTS_PAIR2_SHIFT;
2305 pair1 = (ret & MII_VCT7_RESULTS_PAIR1_MASK) >>
2306 MII_VCT7_RESULTS_PAIR1_SHIFT;
2307 pair0 = (ret & MII_VCT7_RESULTS_PAIR0_MASK) >>
2308 MII_VCT7_RESULTS_PAIR0_SHIFT;
2309
2310 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
2311 marvell_vct7_cable_test_report_trans(pair0));
2312 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
2313 marvell_vct7_cable_test_report_trans(pair1));
2314 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
2315 marvell_vct7_cable_test_report_trans(pair2));
2316 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
2317 marvell_vct7_cable_test_report_trans(pair3));
2318
2319 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, MII_VCT7_CTRL);
2320 if (ret < 0)
2321 return ret;
2322
2323 meter = ret & MII_VCT7_CTRL_METERS;
2324
2325 if (marvell_vct7_distance_valid(pair0))
2326 marvell_vct7_report_length(phydev, 0, meter);
2327 if (marvell_vct7_distance_valid(pair1))
2328 marvell_vct7_report_length(phydev, 1, meter);
2329 if (marvell_vct7_distance_valid(pair2))
2330 marvell_vct7_report_length(phydev, 2, meter);
2331 if (marvell_vct7_distance_valid(pair3))
2332 marvell_vct7_report_length(phydev, 3, meter);
2333
2334 return 0;
2335}
2336
2337static int marvell_vct7_cable_test_get_status(struct phy_device *phydev,
2338 bool *finished)
2339{
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002340 struct marvell_priv *priv = phydev->priv;
Andrew Lunnfc879f72020-05-10 21:12:38 +02002341 int ret;
2342
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02002343 if (priv->cable_test_tdr) {
2344 ret = marvell_vct5_amplitude_graph(phydev);
2345 *finished = true;
2346 return ret;
2347 }
2348
Andrew Lunnfc879f72020-05-10 21:12:38 +02002349 *finished = false;
2350
2351 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,
2352 MII_VCT7_CTRL);
2353
2354 if (ret < 0)
2355 return ret;
2356
2357 if (!(ret & MII_VCT7_CTRL_IN_PROGRESS)) {
2358 *finished = true;
2359
2360 return marvell_vct7_cable_test_report(phydev);
2361 }
2362
2363 return 0;
2364}
2365
Andrew Lunn0b046802017-01-20 01:37:49 +01002366#ifdef CONFIG_HWMON
Marek Behún41d26bf2021-04-20 09:53:59 +02002367struct marvell_hwmon_ops {
Marek Behúna978f7c2021-04-20 09:54:03 +02002368 int (*config)(struct phy_device *phydev);
Marek Behún41d26bf2021-04-20 09:53:59 +02002369 int (*get_temp)(struct phy_device *phydev, long *temp);
2370 int (*get_temp_critical)(struct phy_device *phydev, long *temp);
2371 int (*set_temp_critical)(struct phy_device *phydev, long temp);
2372 int (*get_temp_alarm)(struct phy_device *phydev, long *alarm);
2373};
2374
2375static const struct marvell_hwmon_ops *
2376to_marvell_hwmon_ops(const struct phy_device *phydev)
2377{
2378 return phydev->drv->driver_data;
2379}
2380
Andrew Lunn0b046802017-01-20 01:37:49 +01002381static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
2382{
Andrew Lunn975b3882017-05-25 21:42:06 +02002383 int oldpage;
Russell King424ca4c2018-01-02 10:58:48 +00002384 int ret = 0;
Andrew Lunn0b046802017-01-20 01:37:49 +01002385 int val;
2386
2387 *temp = 0;
2388
Russell King424ca4c2018-01-02 10:58:48 +00002389 oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
2390 if (oldpage < 0)
2391 goto error;
Andrew Lunn975b3882017-05-25 21:42:06 +02002392
Andrew Lunn0b046802017-01-20 01:37:49 +01002393 /* Enable temperature sensor */
Russell King424ca4c2018-01-02 10:58:48 +00002394 ret = __phy_read(phydev, MII_88E1121_MISC_TEST);
Andrew Lunn0b046802017-01-20 01:37:49 +01002395 if (ret < 0)
2396 goto error;
2397
Russell King424ca4c2018-01-02 10:58:48 +00002398 ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
2399 ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
Andrew Lunn0b046802017-01-20 01:37:49 +01002400 if (ret < 0)
2401 goto error;
2402
2403 /* Wait for temperature to stabilize */
2404 usleep_range(10000, 12000);
2405
Russell King424ca4c2018-01-02 10:58:48 +00002406 val = __phy_read(phydev, MII_88E1121_MISC_TEST);
Andrew Lunn0b046802017-01-20 01:37:49 +01002407 if (val < 0) {
2408 ret = val;
2409 goto error;
2410 }
2411
2412 /* Disable temperature sensor */
Russell King424ca4c2018-01-02 10:58:48 +00002413 ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
2414 ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
Andrew Lunn0b046802017-01-20 01:37:49 +01002415 if (ret < 0)
2416 goto error;
2417
2418 *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;
2419
2420error:
Russell King424ca4c2018-01-02 10:58:48 +00002421 return phy_restore_page(phydev, oldpage, ret);
Andrew Lunn0b046802017-01-20 01:37:49 +01002422}
2423
Andrew Lunn0b046802017-01-20 01:37:49 +01002424static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
2425{
2426 int ret;
2427
2428 *temp = 0;
2429
Russell King424ca4c2018-01-02 10:58:48 +00002430 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2431 MII_88E1510_TEMP_SENSOR);
Andrew Lunn0b046802017-01-20 01:37:49 +01002432 if (ret < 0)
Russell King424ca4c2018-01-02 10:58:48 +00002433 return ret;
Andrew Lunn0b046802017-01-20 01:37:49 +01002434
2435 *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;
2436
Russell King424ca4c2018-01-02 10:58:48 +00002437 return 0;
Andrew Lunn0b046802017-01-20 01:37:49 +01002438}
2439
Colin Ian Kingf0a45812017-06-02 15:13:34 +01002440static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
Andrew Lunn0b046802017-01-20 01:37:49 +01002441{
2442 int ret;
2443
2444 *temp = 0;
2445
Russell King424ca4c2018-01-02 10:58:48 +00002446 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2447 MII_88E1121_MISC_TEST);
Andrew Lunn0b046802017-01-20 01:37:49 +01002448 if (ret < 0)
Russell King424ca4c2018-01-02 10:58:48 +00002449 return ret;
Andrew Lunn0b046802017-01-20 01:37:49 +01002450
2451 *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >>
2452 MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25;
2453 /* convert to mC */
2454 *temp *= 1000;
2455
Russell King424ca4c2018-01-02 10:58:48 +00002456 return 0;
Andrew Lunn0b046802017-01-20 01:37:49 +01002457}
2458
Colin Ian Kingf0a45812017-06-02 15:13:34 +01002459static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
Andrew Lunn0b046802017-01-20 01:37:49 +01002460{
Andrew Lunn0b046802017-01-20 01:37:49 +01002461 temp = temp / 1000;
2462 temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
Andrew Lunn0b046802017-01-20 01:37:49 +01002463
Russell King424ca4c2018-01-02 10:58:48 +00002464 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2465 MII_88E1121_MISC_TEST,
2466 MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,
2467 temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);
Andrew Lunn0b046802017-01-20 01:37:49 +01002468}
2469
Colin Ian Kingf0a45812017-06-02 15:13:34 +01002470static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
Andrew Lunn0b046802017-01-20 01:37:49 +01002471{
2472 int ret;
2473
2474 *alarm = false;
2475
Russell King424ca4c2018-01-02 10:58:48 +00002476 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2477 MII_88E1121_MISC_TEST);
Andrew Lunn0b046802017-01-20 01:37:49 +01002478 if (ret < 0)
Russell King424ca4c2018-01-02 10:58:48 +00002479 return ret;
2480
Andrew Lunn0b046802017-01-20 01:37:49 +01002481 *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);
2482
Russell King424ca4c2018-01-02 10:58:48 +00002483 return 0;
Andrew Lunn0b046802017-01-20 01:37:49 +01002484}
2485
Andrew Lunnfee2d542018-01-09 22:42:09 +01002486static int m88e6390_get_temp(struct phy_device *phydev, long *temp)
2487{
2488 int sum = 0;
2489 int oldpage;
2490 int ret = 0;
2491 int i;
2492
2493 *temp = 0;
2494
2495 oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
2496 if (oldpage < 0)
2497 goto error;
2498
2499 /* Enable temperature sensor */
2500 ret = __phy_read(phydev, MII_88E6390_MISC_TEST);
2501 if (ret < 0)
2502 goto error;
2503
Marek Behún00218172021-04-20 09:54:01 +02002504 ret &= ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK;
Marek Behún4f920c292021-04-20 09:54:00 +02002505 ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S;
Andrew Lunnfee2d542018-01-09 22:42:09 +01002506
2507 ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);
2508 if (ret < 0)
2509 goto error;
2510
2511 /* Wait for temperature to stabilize */
2512 usleep_range(10000, 12000);
2513
2514 /* Reading the temperature sense has an errata. You need to read
2515 * a number of times and take an average.
2516 */
2517 for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) {
2518 ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR);
2519 if (ret < 0)
2520 goto error;
2521 sum += ret & MII_88E6390_TEMP_SENSOR_MASK;
2522 }
2523
2524 sum /= MII_88E6390_TEMP_SENSOR_SAMPLES;
2525 *temp = (sum - 75) * 1000;
2526
2527 /* Disable temperature sensor */
2528 ret = __phy_read(phydev, MII_88E6390_MISC_TEST);
2529 if (ret < 0)
2530 goto error;
2531
Marek Behún4f920c292021-04-20 09:54:00 +02002532 ret = ret & ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK;
2533 ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE;
Andrew Lunnfee2d542018-01-09 22:42:09 +01002534
2535 ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);
2536
2537error:
2538 phy_restore_page(phydev, oldpage, ret);
2539
2540 return ret;
2541}
2542
Marek Behúna978f7c2021-04-20 09:54:03 +02002543static int m88e6393_get_temp(struct phy_device *phydev, long *temp)
2544{
2545 int err;
2546
2547 err = m88e1510_get_temp(phydev, temp);
2548
2549 /* 88E1510 measures T + 25, while the PHY on 88E6393X switch
2550 * T + 75, so we have to subtract another 50
2551 */
2552 *temp -= 50000;
2553
2554 return err;
2555}
2556
2557static int m88e6393_get_temp_critical(struct phy_device *phydev, long *temp)
2558{
2559 int ret;
2560
2561 *temp = 0;
2562
2563 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2564 MII_88E6390_TEMP_SENSOR);
2565 if (ret < 0)
2566 return ret;
2567
2568 *temp = (((ret & MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK) >>
2569 MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT) - 75) * 1000;
2570
2571 return 0;
2572}
2573
2574static int m88e6393_set_temp_critical(struct phy_device *phydev, long temp)
2575{
2576 temp = (temp / 1000) + 75;
2577
2578 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2579 MII_88E6390_TEMP_SENSOR,
2580 MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK,
2581 temp << MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT);
2582}
2583
2584static int m88e6393_hwmon_config(struct phy_device *phydev)
2585{
2586 int err;
2587
2588 err = m88e6393_set_temp_critical(phydev, 100000);
2589 if (err)
2590 return err;
2591
2592 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
2593 MII_88E6390_MISC_TEST,
2594 MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK |
2595 MII_88E6393_MISC_TEST_SAMPLES_MASK |
2596 MII_88E6393_MISC_TEST_RATE_MASK,
2597 MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE |
2598 MII_88E6393_MISC_TEST_SAMPLES_2048 |
2599 MII_88E6393_MISC_TEST_RATE_2_3MS);
2600}
2601
Marek Behún41d26bf2021-04-20 09:53:59 +02002602static int marvell_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
2603 u32 attr, int channel, long *temp)
Andrew Lunnfee2d542018-01-09 22:42:09 +01002604{
2605 struct phy_device *phydev = dev_get_drvdata(dev);
Marek Behún41d26bf2021-04-20 09:53:59 +02002606 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);
2607 int err = -EOPNOTSUPP;
Andrew Lunnfee2d542018-01-09 22:42:09 +01002608
2609 switch (attr) {
2610 case hwmon_temp_input:
Marek Behún41d26bf2021-04-20 09:53:59 +02002611 if (ops->get_temp)
2612 err = ops->get_temp(phydev, temp);
Andrew Lunnfee2d542018-01-09 22:42:09 +01002613 break;
Marek Behún41d26bf2021-04-20 09:53:59 +02002614 case hwmon_temp_crit:
2615 if (ops->get_temp_critical)
2616 err = ops->get_temp_critical(phydev, temp);
2617 break;
2618 case hwmon_temp_max_alarm:
2619 if (ops->get_temp_alarm)
2620 err = ops->get_temp_alarm(phydev, temp);
2621 break;
Andrew Lunnfee2d542018-01-09 22:42:09 +01002622 }
2623
2624 return err;
2625}
2626
Marek Behún41d26bf2021-04-20 09:53:59 +02002627static int marvell_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
2628 u32 attr, int channel, long temp)
Andrew Lunnfee2d542018-01-09 22:42:09 +01002629{
Marek Behún41d26bf2021-04-20 09:53:59 +02002630 struct phy_device *phydev = dev_get_drvdata(dev);
2631 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);
2632 int err = -EOPNOTSUPP;
2633
2634 switch (attr) {
2635 case hwmon_temp_crit:
2636 if (ops->set_temp_critical)
2637 err = ops->set_temp_critical(phydev, temp);
2638 break;
Marek Behún41d26bf2021-04-20 09:53:59 +02002639 }
2640
2641 return err;
2642}
2643
2644static umode_t marvell_hwmon_is_visible(const void *data,
2645 enum hwmon_sensor_types type,
2646 u32 attr, int channel)
2647{
2648 const struct phy_device *phydev = data;
2649 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);
2650
Andrew Lunnfee2d542018-01-09 22:42:09 +01002651 if (type != hwmon_temp)
2652 return 0;
2653
2654 switch (attr) {
2655 case hwmon_temp_input:
Marek Behún41d26bf2021-04-20 09:53:59 +02002656 return ops->get_temp ? 0444 : 0;
2657 case hwmon_temp_max_alarm:
2658 return ops->get_temp_alarm ? 0444 : 0;
2659 case hwmon_temp_crit:
2660 return (ops->get_temp_critical ? 0444 : 0) |
2661 (ops->set_temp_critical ? 0200 : 0);
Andrew Lunnfee2d542018-01-09 22:42:09 +01002662 default:
2663 return 0;
2664 }
2665}
2666
Marek Behún41d26bf2021-04-20 09:53:59 +02002667static u32 marvell_hwmon_chip_config[] = {
2668 HWMON_C_REGISTER_TZ,
Andrew Lunnfee2d542018-01-09 22:42:09 +01002669 0
2670};
2671
Marek Behún41d26bf2021-04-20 09:53:59 +02002672static const struct hwmon_channel_info marvell_hwmon_chip = {
2673 .type = hwmon_chip,
2674 .config = marvell_hwmon_chip_config,
Andrew Lunnfee2d542018-01-09 22:42:09 +01002675};
2676
Marek Behún41d26bf2021-04-20 09:53:59 +02002677/* we can define HWMON_T_CRIT and HWMON_T_MAX_ALARM even though these are not
2678 * defined for all PHYs, because the hwmon code checks whether the attributes
2679 * exists via the .is_visible method
2680 */
2681static u32 marvell_hwmon_temp_config[] = {
2682 HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM,
2683 0
2684};
2685
2686static const struct hwmon_channel_info marvell_hwmon_temp = {
2687 .type = hwmon_temp,
2688 .config = marvell_hwmon_temp_config,
2689};
2690
2691static const struct hwmon_channel_info *marvell_hwmon_info[] = {
2692 &marvell_hwmon_chip,
2693 &marvell_hwmon_temp,
Andrew Lunnfee2d542018-01-09 22:42:09 +01002694 NULL
2695};
2696
Marek Behún41d26bf2021-04-20 09:53:59 +02002697static const struct hwmon_ops marvell_hwmon_hwmon_ops = {
2698 .is_visible = marvell_hwmon_is_visible,
2699 .read = marvell_hwmon_read,
2700 .write = marvell_hwmon_write,
Andrew Lunnfee2d542018-01-09 22:42:09 +01002701};
2702
Marek Behún41d26bf2021-04-20 09:53:59 +02002703static const struct hwmon_chip_info marvell_hwmon_chip_info = {
2704 .ops = &marvell_hwmon_hwmon_ops,
2705 .info = marvell_hwmon_info,
Andrew Lunnfee2d542018-01-09 22:42:09 +01002706};
2707
Andrew Lunn0b046802017-01-20 01:37:49 +01002708static int marvell_hwmon_name(struct phy_device *phydev)
2709{
2710 struct marvell_priv *priv = phydev->priv;
2711 struct device *dev = &phydev->mdio.dev;
2712 const char *devname = dev_name(dev);
2713 size_t len = strlen(devname);
2714 int i, j;
2715
2716 priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL);
2717 if (!priv->hwmon_name)
2718 return -ENOMEM;
2719
2720 for (i = j = 0; i < len && devname[i]; i++) {
2721 if (isalnum(devname[i]))
2722 priv->hwmon_name[j++] = devname[i];
2723 }
2724
2725 return 0;
2726}
2727
Marek Behún41d26bf2021-04-20 09:53:59 +02002728static int marvell_hwmon_probe(struct phy_device *phydev)
Andrew Lunn0b046802017-01-20 01:37:49 +01002729{
Marek Behún41d26bf2021-04-20 09:53:59 +02002730 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);
Andrew Lunn0b046802017-01-20 01:37:49 +01002731 struct marvell_priv *priv = phydev->priv;
2732 struct device *dev = &phydev->mdio.dev;
2733 int err;
2734
Marek Behún41d26bf2021-04-20 09:53:59 +02002735 if (!ops)
2736 return 0;
2737
Andrew Lunn0b046802017-01-20 01:37:49 +01002738 err = marvell_hwmon_name(phydev);
2739 if (err)
2740 return err;
2741
2742 priv->hwmon_dev = devm_hwmon_device_register_with_info(
Marek Behún41d26bf2021-04-20 09:53:59 +02002743 dev, priv->hwmon_name, phydev, &marvell_hwmon_chip_info, NULL);
Marek Behúna978f7c2021-04-20 09:54:03 +02002744 if (IS_ERR(priv->hwmon_dev))
2745 return PTR_ERR(priv->hwmon_dev);
Andrew Lunn0b046802017-01-20 01:37:49 +01002746
Marek Behúna978f7c2021-04-20 09:54:03 +02002747 if (ops->config)
2748 err = ops->config(phydev);
2749
2750 return err;
Andrew Lunn0b046802017-01-20 01:37:49 +01002751}
2752
Marek Behún41d26bf2021-04-20 09:53:59 +02002753static const struct marvell_hwmon_ops m88e1121_hwmon_ops = {
2754 .get_temp = m88e1121_get_temp,
2755};
Andrew Lunn0b046802017-01-20 01:37:49 +01002756
Marek Behún41d26bf2021-04-20 09:53:59 +02002757static const struct marvell_hwmon_ops m88e1510_hwmon_ops = {
2758 .get_temp = m88e1510_get_temp,
2759 .get_temp_critical = m88e1510_get_temp_critical,
2760 .set_temp_critical = m88e1510_set_temp_critical,
2761 .get_temp_alarm = m88e1510_get_temp_alarm,
2762};
Andrew Lunnfee2d542018-01-09 22:42:09 +01002763
Marek Behún41d26bf2021-04-20 09:53:59 +02002764static const struct marvell_hwmon_ops m88e6390_hwmon_ops = {
2765 .get_temp = m88e6390_get_temp,
2766};
2767
Marek Behúna978f7c2021-04-20 09:54:03 +02002768static const struct marvell_hwmon_ops m88e6393_hwmon_ops = {
2769 .config = m88e6393_hwmon_config,
2770 .get_temp = m88e6393_get_temp,
2771 .get_temp_critical = m88e6393_get_temp_critical,
2772 .set_temp_critical = m88e6393_set_temp_critical,
2773 .get_temp_alarm = m88e1510_get_temp_alarm,
2774};
2775
Marek Behún41d26bf2021-04-20 09:53:59 +02002776#define DEF_MARVELL_HWMON_OPS(s) (&(s))
2777
Andrew Lunn0b046802017-01-20 01:37:49 +01002778#else
Andrew Lunn0b046802017-01-20 01:37:49 +01002779
Marek Behún41d26bf2021-04-20 09:53:59 +02002780#define DEF_MARVELL_HWMON_OPS(s) NULL
Andrew Lunnfee2d542018-01-09 22:42:09 +01002781
Marek Behún41d26bf2021-04-20 09:53:59 +02002782static int marvell_hwmon_probe(struct phy_device *phydev)
Andrew Lunnfee2d542018-01-09 22:42:09 +01002783{
2784 return 0;
2785}
Andrew Lunn0b046802017-01-20 01:37:49 +01002786#endif
2787
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002788static int marvell_probe(struct phy_device *phydev)
2789{
2790 struct marvell_priv *priv;
2791
Andrew Lunne5a03bf2016-01-06 20:11:16 +01002792 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002793 if (!priv)
2794 return -ENOMEM;
2795
2796 phydev->priv = priv;
2797
Marek Behún41d26bf2021-04-20 09:53:59 +02002798 return marvell_hwmon_probe(phydev);
Andrew Lunnfee2d542018-01-09 22:42:09 +01002799}
2800
Ivan Bornyakovb697d9d2021-08-12 16:42:56 +03002801static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
2802{
2803 struct phy_device *phydev = upstream;
2804 phy_interface_t interface;
2805 struct device *dev;
2806 int oldpage;
2807 int ret = 0;
2808 u16 mode;
2809
2810 __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
2811
2812 dev = &phydev->mdio.dev;
2813
2814 sfp_parse_support(phydev->sfp_bus, id, supported);
2815 interface = sfp_select_interface(phydev->sfp_bus, supported);
2816
2817 dev_info(dev, "%s SFP module inserted\n", phy_modes(interface));
2818
2819 switch (interface) {
2820 case PHY_INTERFACE_MODE_1000BASEX:
2821 mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X;
2822
2823 break;
2824 case PHY_INTERFACE_MODE_100BASEX:
2825 mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX;
2826
2827 break;
2828 case PHY_INTERFACE_MODE_SGMII:
2829 mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII;
2830
2831 break;
2832 default:
2833 dev_err(dev, "Incompatible SFP module inserted\n");
2834
2835 return -EINVAL;
2836 }
2837
2838 oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);
2839 if (oldpage < 0)
2840 goto error;
2841
2842 ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
2843 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, mode);
2844 if (ret < 0)
2845 goto error;
2846
2847 ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,
2848 MII_88E1510_GEN_CTRL_REG_1_RESET);
2849
2850error:
2851 return phy_restore_page(phydev, oldpage, ret);
2852}
2853
2854static void m88e1510_sfp_remove(void *upstream)
2855{
2856 struct phy_device *phydev = upstream;
2857 int oldpage;
2858 int ret = 0;
2859
2860 oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);
2861 if (oldpage < 0)
2862 goto error;
2863
2864 ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
2865 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,
2866 MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII);
2867 if (ret < 0)
2868 goto error;
2869
2870 ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,
2871 MII_88E1510_GEN_CTRL_REG_1_RESET);
2872
2873error:
2874 phy_restore_page(phydev, oldpage, ret);
2875}
2876
2877static const struct sfp_upstream_ops m88e1510_sfp_ops = {
2878 .module_insert = m88e1510_sfp_insert,
2879 .module_remove = m88e1510_sfp_remove,
2880 .attach = phy_sfp_attach,
2881 .detach = phy_sfp_detach,
2882};
2883
2884static int m88e1510_probe(struct phy_device *phydev)
2885{
2886 int err;
2887
2888 err = marvell_probe(phydev);
2889 if (err)
2890 return err;
2891
2892 return phy_sfp_probe(phydev, &m88e1510_sfp_ops);
2893}
2894
Olof Johanssone5479232007-07-03 16:23:46 -05002895static struct phy_driver marvell_drivers[] = {
2896 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10002897 .phy_id = MARVELL_PHY_ID_88E1101,
2898 .phy_id_mask = MARVELL_PHY_ID_MASK,
Olof Johanssone5479232007-07-03 16:23:46 -05002899 .name = "Marvell 88E1101",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002900 /* PHY_GBIT_FEATURES */
Arnd Bergmann18702412017-01-23 13:18:41 +01002901 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002902 .config_init = marvell_config_init,
2903 .config_aneg = m88e1101_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002904 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02002905 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002906 .resume = genphy_resume,
2907 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00002908 .read_page = marvell_read_page,
2909 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002910 .get_sset_count = marvell_get_sset_count,
2911 .get_strings = marvell_get_strings,
2912 .get_stats = marvell_get_stats,
Olof Johanssone5479232007-07-03 16:23:46 -05002913 },
2914 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10002915 .phy_id = MARVELL_PHY_ID_88E1112,
2916 .phy_id_mask = MARVELL_PHY_ID_MASK,
Olof Johansson85cfb532007-07-03 16:24:32 -05002917 .name = "Marvell 88E1112",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002918 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002919 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03002920 .config_init = m88e1112_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002921 .config_aneg = marvell_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002922 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02002923 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002924 .resume = genphy_resume,
2925 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00002926 .read_page = marvell_read_page,
2927 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002928 .get_sset_count = marvell_get_sset_count,
2929 .get_strings = marvell_get_strings,
2930 .get_stats = marvell_get_stats,
Heiner Kallweit262caf42019-10-28 20:54:17 +01002931 .get_tunable = m88e1011_get_tunable,
2932 .set_tunable = m88e1011_set_tunable,
Olof Johansson85cfb532007-07-03 16:24:32 -05002933 },
2934 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10002935 .phy_id = MARVELL_PHY_ID_88E1111,
2936 .phy_id_mask = MARVELL_PHY_ID_MASK,
Olof Johanssone5479232007-07-03 16:23:46 -05002937 .name = "Marvell 88E1111",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002938 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002939 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03002940 .config_init = m88e1111gbe_config_init,
Robert Hancock18870232020-10-28 11:15:40 -06002941 .config_aneg = m88e1111_config_aneg,
2942 .read_status = marvell_read_status,
Robert Hancock18870232020-10-28 11:15:40 -06002943 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02002944 .handle_interrupt = marvell_handle_interrupt,
Robert Hancock18870232020-10-28 11:15:40 -06002945 .resume = genphy_resume,
2946 .suspend = genphy_suspend,
2947 .read_page = marvell_read_page,
2948 .write_page = marvell_write_page,
2949 .get_sset_count = marvell_get_sset_count,
2950 .get_strings = marvell_get_strings,
2951 .get_stats = marvell_get_stats,
2952 .get_tunable = m88e1111_get_tunable,
2953 .set_tunable = m88e1111_set_tunable,
2954 },
2955 {
2956 .phy_id = MARVELL_PHY_ID_88E1111_FINISAR,
2957 .phy_id_mask = MARVELL_PHY_ID_MASK,
2958 .name = "Marvell 88E1111 (Finisar)",
2959 /* PHY_GBIT_FEATURES */
2960 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03002961 .config_init = m88e1111gbe_config_init,
Robert Hancock18870232020-10-28 11:15:40 -06002962 .config_aneg = m88e1111_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002963 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002964 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02002965 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002966 .resume = genphy_resume,
2967 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00002968 .read_page = marvell_read_page,
2969 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002970 .get_sset_count = marvell_get_sset_count,
2971 .get_strings = marvell_get_strings,
2972 .get_stats = marvell_get_stats,
Heiner Kallweit5c6bc512019-10-28 20:53:25 +01002973 .get_tunable = m88e1111_get_tunable,
2974 .set_tunable = m88e1111_set_tunable,
Olof Johanssone5479232007-07-03 16:23:46 -05002975 },
2976 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10002977 .phy_id = MARVELL_PHY_ID_88E1118,
2978 .phy_id_mask = MARVELL_PHY_ID_MASK,
Ron Madrid605f1962008-11-06 09:05:26 +00002979 .name = "Marvell 88E1118",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002980 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002981 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002982 .config_init = m88e1118_config_init,
2983 .config_aneg = m88e1118_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002984 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02002985 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03002986 .resume = genphy_resume,
2987 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00002988 .read_page = marvell_read_page,
2989 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01002990 .get_sset_count = marvell_get_sset_count,
2991 .get_strings = marvell_get_strings,
2992 .get_stats = marvell_get_stats,
Ron Madrid605f1962008-11-06 09:05:26 +00002993 },
2994 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10002995 .phy_id = MARVELL_PHY_ID_88E1121R,
2996 .phy_id_mask = MARVELL_PHY_ID_MASK,
Sergei Poselenov140bc922009-04-07 02:01:41 +00002997 .name = "Marvell 88E1121R",
Marek Behún41d26bf2021-04-20 09:53:59 +02002998 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1121_hwmon_ops),
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002999 /* PHY_GBIT_FEATURES */
Marek Behún41d26bf2021-04-20 09:53:59 +02003000 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003001 .config_init = marvell_1011gbe_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003002 .config_aneg = m88e1121_config_aneg,
3003 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003004 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003005 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003006 .resume = genphy_resume,
3007 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003008 .read_page = marvell_read_page,
3009 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003010 .get_sset_count = marvell_get_sset_count,
3011 .get_strings = marvell_get_strings,
3012 .get_stats = marvell_get_stats,
Heiner Kallweit911af5e2019-10-28 20:52:55 +01003013 .get_tunable = m88e1011_get_tunable,
3014 .set_tunable = m88e1011_set_tunable,
Sergei Poselenov140bc922009-04-07 02:01:41 +00003015 },
3016 {
Cyril Chemparathy337ac9d2010-10-29 13:50:25 -07003017 .phy_id = MARVELL_PHY_ID_88E1318S,
Linus Torvalds6ba74012010-08-04 11:47:58 -07003018 .phy_id_mask = MARVELL_PHY_ID_MASK,
Cyril Chemparathy337ac9d2010-10-29 13:50:25 -07003019 .name = "Marvell 88E1318S",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003020 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003021 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003022 .config_init = m88e1318_config_init,
3023 .config_aneg = m88e1318_config_aneg,
3024 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003025 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003026 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003027 .get_wol = m88e1318_get_wol,
3028 .set_wol = m88e1318_set_wol,
3029 .resume = genphy_resume,
3030 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003031 .read_page = marvell_read_page,
3032 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003033 .get_sset_count = marvell_get_sset_count,
3034 .get_strings = marvell_get_strings,
3035 .get_stats = marvell_get_stats,
Cyril Chemparathy3ff1c252010-08-03 19:36:06 -07003036 },
3037 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10003038 .phy_id = MARVELL_PHY_ID_88E1145,
3039 .phy_id_mask = MARVELL_PHY_ID_MASK,
Olof Johanssone5479232007-07-03 16:23:46 -05003040 .name = "Marvell 88E1145",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003041 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003042 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003043 .config_init = m88e1145_config_init,
3044 .config_aneg = m88e1101_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003045 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003046 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003047 .resume = genphy_resume,
3048 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003049 .read_page = marvell_read_page,
3050 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003051 .get_sset_count = marvell_get_sset_count,
3052 .get_strings = marvell_get_strings,
3053 .get_stats = marvell_get_stats,
Heiner Kallweita319fb52019-10-29 20:25:26 +01003054 .get_tunable = m88e1111_get_tunable,
3055 .set_tunable = m88e1111_set_tunable,
Olof Johanssonac8c6352007-11-04 16:08:51 -06003056 },
3057 {
David Daney90600732010-11-19 11:58:53 +00003058 .phy_id = MARVELL_PHY_ID_88E1149R,
3059 .phy_id_mask = MARVELL_PHY_ID_MASK,
3060 .name = "Marvell 88E1149R",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003061 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003062 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003063 .config_init = m88e1149_config_init,
3064 .config_aneg = m88e1118_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003065 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003066 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003067 .resume = genphy_resume,
3068 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003069 .read_page = marvell_read_page,
3070 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003071 .get_sset_count = marvell_get_sset_count,
3072 .get_strings = marvell_get_strings,
3073 .get_stats = marvell_get_stats,
David Daney90600732010-11-19 11:58:53 +00003074 },
3075 {
Benjamin Herrenschmidt2f495c32010-06-21 13:20:46 +10003076 .phy_id = MARVELL_PHY_ID_88E1240,
3077 .phy_id_mask = MARVELL_PHY_ID_MASK,
Olof Johanssonac8c6352007-11-04 16:08:51 -06003078 .name = "Marvell 88E1240",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003079 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003080 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003081 .config_init = m88e1112_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003082 .config_aneg = marvell_config_aneg,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003083 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003084 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003085 .resume = genphy_resume,
3086 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003087 .read_page = marvell_read_page,
3088 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003089 .get_sset_count = marvell_get_sset_count,
3090 .get_strings = marvell_get_strings,
3091 .get_stats = marvell_get_stats,
Maxim Kochetkov65ad85f2021-04-28 12:53:56 +03003092 .get_tunable = m88e1011_get_tunable,
3093 .set_tunable = m88e1011_set_tunable,
Olof Johanssonac8c6352007-11-04 16:08:51 -06003094 },
Michal Simek3da09a52013-05-30 20:08:26 +00003095 {
3096 .phy_id = MARVELL_PHY_ID_88E1116R,
3097 .phy_id_mask = MARVELL_PHY_ID_MASK,
3098 .name = "Marvell 88E1116R",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003099 /* PHY_GBIT_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003100 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003101 .config_init = m88e1116r_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003102 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003103 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003104 .resume = genphy_resume,
3105 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003106 .read_page = marvell_read_page,
3107 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003108 .get_sset_count = marvell_get_sset_count,
3109 .get_strings = marvell_get_strings,
3110 .get_stats = marvell_get_stats,
Heiner Kallweit262caf42019-10-28 20:54:17 +01003111 .get_tunable = m88e1011_get_tunable,
3112 .set_tunable = m88e1011_set_tunable,
Michal Simek3da09a52013-05-30 20:08:26 +00003113 },
Michal Simek10e24caa2013-05-30 20:08:27 +00003114 {
3115 .phy_id = MARVELL_PHY_ID_88E1510,
3116 .phy_id_mask = MARVELL_PHY_ID_MASK,
3117 .name = "Marvell 88E1510",
Marek Behún41d26bf2021-04-20 09:53:59 +02003118 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
Andrew Lunn719655a2018-09-29 23:04:16 +02003119 .features = PHY_GBIT_FIBRE_FEATURES,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003120 .flags = PHY_POLL_CABLE_TEST,
Ivan Bornyakovb697d9d2021-08-12 16:42:56 +03003121 .probe = m88e1510_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003122 .config_init = m88e1510_config_init,
3123 .config_aneg = m88e1510_config_aneg,
3124 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003125 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003126 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003127 .get_wol = m88e1318_get_wol,
3128 .set_wol = m88e1318_set_wol,
3129 .resume = marvell_resume,
3130 .suspend = marvell_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003131 .read_page = marvell_read_page,
3132 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003133 .get_sset_count = marvell_get_sset_count,
3134 .get_strings = marvell_get_strings,
3135 .get_stats = marvell_get_stats,
Mohammad Athari Bin Ismail020a45a2022-01-15 17:25:15 +08003136 .set_loopback = m88e1510_loopback,
Heiner Kallweit262caf42019-10-28 20:54:17 +01003137 .get_tunable = m88e1011_get_tunable,
3138 .set_tunable = m88e1011_set_tunable,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003139 .cable_test_start = marvell_vct7_cable_test_start,
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02003140 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003141 .cable_test_get_status = marvell_vct7_cable_test_get_status,
Michal Simek10e24caa2013-05-30 20:08:27 +00003142 },
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +02003143 {
Andrew Lunn819ec8e2015-11-16 23:34:41 +01003144 .phy_id = MARVELL_PHY_ID_88E1540,
3145 .phy_id_mask = MARVELL_PHY_ID_MASK,
3146 .name = "Marvell 88E1540",
Marek Behún41d26bf2021-04-20 09:53:59 +02003147 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003148 /* PHY_GBIT_FEATURES */
Andrew Lunnfc879f72020-05-10 21:12:38 +02003149 .flags = PHY_POLL_CABLE_TEST,
Marek Behún41d26bf2021-04-20 09:53:59 +02003150 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003151 .config_init = marvell_1011gbe_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003152 .config_aneg = m88e1510_config_aneg,
3153 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003154 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003155 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003156 .resume = genphy_resume,
3157 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003158 .read_page = marvell_read_page,
3159 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003160 .get_sset_count = marvell_get_sset_count,
3161 .get_strings = marvell_get_strings,
3162 .get_stats = marvell_get_stats,
Heiner Kallweit69f42be2019-03-25 19:35:41 +01003163 .get_tunable = m88e1540_get_tunable,
3164 .set_tunable = m88e1540_set_tunable,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003165 .cable_test_start = marvell_vct7_cable_test_start,
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02003166 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003167 .cable_test_get_status = marvell_vct7_cable_test_get_status,
Andrew Lunn819ec8e2015-11-16 23:34:41 +01003168 },
3169 {
Andrew Lunn60f06fd2017-02-02 00:35:03 +01003170 .phy_id = MARVELL_PHY_ID_88E1545,
3171 .phy_id_mask = MARVELL_PHY_ID_MASK,
3172 .name = "Marvell 88E1545",
Marek Behún41d26bf2021-04-20 09:53:59 +02003173 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
3174 .probe = marvell_probe,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003175 /* PHY_GBIT_FEATURES */
Andrew Lunnfc879f72020-05-10 21:12:38 +02003176 .flags = PHY_POLL_CABLE_TEST,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003177 .config_init = marvell_1011gbe_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003178 .config_aneg = m88e1510_config_aneg,
3179 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003180 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003181 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003182 .resume = genphy_resume,
3183 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003184 .read_page = marvell_read_page,
3185 .write_page = marvell_write_page,
Andrew Lunn60f06fd2017-02-02 00:35:03 +01003186 .get_sset_count = marvell_get_sset_count,
3187 .get_strings = marvell_get_strings,
3188 .get_stats = marvell_get_stats,
Heiner Kallweit262caf42019-10-28 20:54:17 +01003189 .get_tunable = m88e1540_get_tunable,
3190 .set_tunable = m88e1540_set_tunable,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003191 .cable_test_start = marvell_vct7_cable_test_start,
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02003192 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003193 .cable_test_get_status = marvell_vct7_cable_test_get_status,
Andrew Lunn60f06fd2017-02-02 00:35:03 +01003194 },
3195 {
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +02003196 .phy_id = MARVELL_PHY_ID_88E3016,
3197 .phy_id_mask = MARVELL_PHY_ID_MASK,
3198 .name = "Marvell 88E3016",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003199 /* PHY_BASIC_FEATURES */
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003200 .probe = marvell_probe,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003201 .config_init = m88e3016_config_init,
3202 .aneg_done = marvell_aneg_done,
3203 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003204 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003205 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003206 .resume = genphy_resume,
3207 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003208 .read_page = marvell_read_page,
3209 .write_page = marvell_write_page,
Andrew Lunnd2fa47d2015-12-30 16:28:26 +01003210 .get_sset_count = marvell_get_sset_count,
3211 .get_strings = marvell_get_strings,
3212 .get_stats = marvell_get_stats,
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +02003213 },
Andrew Lunne4cf8a32017-02-01 03:40:06 +01003214 {
Pali Rohár1fe976d2021-04-12 18:57:39 +02003215 .phy_id = MARVELL_PHY_ID_88E6341_FAMILY,
Andrew Lunne4cf8a32017-02-01 03:40:06 +01003216 .phy_id_mask = MARVELL_PHY_ID_MASK,
Pali Rohár1fe976d2021-04-12 18:57:39 +02003217 .name = "Marvell 88E6341 Family",
Marek Behún41d26bf2021-04-20 09:53:59 +02003218 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
Pali Rohár1fe976d2021-04-12 18:57:39 +02003219 /* PHY_GBIT_FEATURES */
3220 .flags = PHY_POLL_CABLE_TEST,
Marek Behún41d26bf2021-04-20 09:53:59 +02003221 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003222 .config_init = marvell_1011gbe_config_init,
Pali Rohár1fe976d2021-04-12 18:57:39 +02003223 .config_aneg = m88e6390_config_aneg,
3224 .read_status = marvell_read_status,
3225 .config_intr = marvell_config_intr,
3226 .handle_interrupt = marvell_handle_interrupt,
3227 .resume = genphy_resume,
3228 .suspend = genphy_suspend,
3229 .read_page = marvell_read_page,
3230 .write_page = marvell_write_page,
3231 .get_sset_count = marvell_get_sset_count,
3232 .get_strings = marvell_get_strings,
3233 .get_stats = marvell_get_stats,
3234 .get_tunable = m88e1540_get_tunable,
3235 .set_tunable = m88e1540_set_tunable,
3236 .cable_test_start = marvell_vct7_cable_test_start,
3237 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
3238 .cable_test_get_status = marvell_vct7_cable_test_get_status,
3239 },
3240 {
3241 .phy_id = MARVELL_PHY_ID_88E6390_FAMILY,
3242 .phy_id_mask = MARVELL_PHY_ID_MASK,
3243 .name = "Marvell 88E6390 Family",
Marek Behún41d26bf2021-04-20 09:53:59 +02003244 .driver_data = DEF_MARVELL_HWMON_OPS(m88e6390_hwmon_ops),
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02003245 /* PHY_GBIT_FEATURES */
Andrew Lunnfc879f72020-05-10 21:12:38 +02003246 .flags = PHY_POLL_CABLE_TEST,
Marek Behún41d26bf2021-04-20 09:53:59 +02003247 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003248 .config_init = marvell_1011gbe_config_init,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003249 .config_aneg = m88e6390_config_aneg,
3250 .read_status = marvell_read_status,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003251 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003252 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovef0f9542020-06-21 10:59:50 +03003253 .resume = genphy_resume,
3254 .suspend = genphy_suspend,
Russell King424ca4c2018-01-02 10:58:48 +00003255 .read_page = marvell_read_page,
3256 .write_page = marvell_write_page,
Andrew Lunne4cf8a32017-02-01 03:40:06 +01003257 .get_sset_count = marvell_get_sset_count,
3258 .get_strings = marvell_get_strings,
3259 .get_stats = marvell_get_stats,
Heiner Kallweit69f42be2019-03-25 19:35:41 +01003260 .get_tunable = m88e1540_get_tunable,
3261 .set_tunable = m88e1540_set_tunable,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003262 .cable_test_start = marvell_vct7_cable_test_start,
Andrew Lunn0c9bcc12020-05-27 00:21:40 +02003263 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
Andrew Lunnfc879f72020-05-10 21:12:38 +02003264 .cable_test_get_status = marvell_vct7_cable_test_get_status,
Andrew Lunne4cf8a32017-02-01 03:40:06 +01003265 },
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003266 {
Marek Behúna978f7c2021-04-20 09:54:03 +02003267 .phy_id = MARVELL_PHY_ID_88E6393_FAMILY,
3268 .phy_id_mask = MARVELL_PHY_ID_MASK,
3269 .name = "Marvell 88E6393 Family",
3270 .driver_data = DEF_MARVELL_HWMON_OPS(m88e6393_hwmon_ops),
3271 /* PHY_GBIT_FEATURES */
3272 .flags = PHY_POLL_CABLE_TEST,
3273 .probe = marvell_probe,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003274 .config_init = marvell_1011gbe_config_init,
Marek Behúna978f7c2021-04-20 09:54:03 +02003275 .config_aneg = m88e1510_config_aneg,
3276 .read_status = marvell_read_status,
3277 .config_intr = marvell_config_intr,
3278 .handle_interrupt = marvell_handle_interrupt,
3279 .resume = genphy_resume,
3280 .suspend = genphy_suspend,
3281 .read_page = marvell_read_page,
3282 .write_page = marvell_write_page,
3283 .get_sset_count = marvell_get_sset_count,
3284 .get_strings = marvell_get_strings,
3285 .get_stats = marvell_get_stats,
3286 .get_tunable = m88e1540_get_tunable,
3287 .set_tunable = m88e1540_set_tunable,
3288 .cable_test_start = marvell_vct7_cable_test_start,
3289 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
3290 .cable_test_get_status = marvell_vct7_cable_test_get_status,
3291 },
3292 {
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003293 .phy_id = MARVELL_PHY_ID_88E1340S,
3294 .phy_id_mask = MARVELL_PHY_ID_MASK,
3295 .name = "Marvell 88E1340S",
Marek Behún41d26bf2021-04-20 09:53:59 +02003296 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
3297 .probe = marvell_probe,
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003298 /* PHY_GBIT_FEATURES */
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003299 .config_init = marvell_1011gbe_config_init,
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003300 .config_aneg = m88e1510_config_aneg,
3301 .read_status = marvell_read_status,
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003302 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003303 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003304 .resume = genphy_resume,
3305 .suspend = genphy_suspend,
3306 .read_page = marvell_read_page,
3307 .write_page = marvell_write_page,
3308 .get_sset_count = marvell_get_sset_count,
3309 .get_strings = marvell_get_strings,
3310 .get_stats = marvell_get_stats,
3311 .get_tunable = m88e1540_get_tunable,
3312 .set_tunable = m88e1540_set_tunable,
3313 },
Maxim Kochetkovf59babf2020-06-21 10:59:52 +03003314 {
3315 .phy_id = MARVELL_PHY_ID_88E1548P,
3316 .phy_id_mask = MARVELL_PHY_ID_MASK,
3317 .name = "Marvell 88E1548P",
Marek Behún41d26bf2021-04-20 09:53:59 +02003318 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),
3319 .probe = marvell_probe,
Maxim Kochetkovf59babf2020-06-21 10:59:52 +03003320 .features = PHY_GBIT_FIBRE_FEATURES,
Maxim Kochetkov8385b1f2021-04-30 07:57:33 +03003321 .config_init = marvell_1011gbe_config_init,
Maxim Kochetkovf59babf2020-06-21 10:59:52 +03003322 .config_aneg = m88e1510_config_aneg,
3323 .read_status = marvell_read_status,
Maxim Kochetkovf59babf2020-06-21 10:59:52 +03003324 .config_intr = marvell_config_intr,
Ioana Ciorneia0723b32020-11-13 18:52:13 +02003325 .handle_interrupt = marvell_handle_interrupt,
Maxim Kochetkovf59babf2020-06-21 10:59:52 +03003326 .resume = genphy_resume,
3327 .suspend = genphy_suspend,
3328 .read_page = marvell_read_page,
3329 .write_page = marvell_write_page,
3330 .get_sset_count = marvell_get_sset_count,
3331 .get_strings = marvell_get_strings,
3332 .get_stats = marvell_get_stats,
3333 .get_tunable = m88e1540_get_tunable,
3334 .set_tunable = m88e1540_set_tunable,
3335 },
Andy Fleming00db8182005-07-30 19:31:23 -04003336};
3337
Johan Hovold50fd7152014-11-11 19:45:59 +01003338module_phy_driver(marvell_drivers);
David Woodhouse4e4f10f2010-04-02 01:05:56 +00003339
Uwe Kleine-Königcf93c942010-10-03 23:43:32 +00003340static struct mdio_device_id __maybe_unused marvell_tbl[] = {
Michal Simekf5e1cab2013-05-30 20:08:25 +00003341 { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
3342 { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
3343 { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
Robert Hancock18870232020-10-28 11:15:40 -06003344 { MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK },
Michal Simekf5e1cab2013-05-30 20:08:25 +00003345 { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
3346 { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
3347 { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
3348 { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
3349 { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
3350 { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
Michal Simek3da09a52013-05-30 20:08:26 +00003351 { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
Michal Simek10e24caa2013-05-30 20:08:27 +00003352 { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
Andrew Lunn819ec8e2015-11-16 23:34:41 +01003353 { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
Andrew Lunn60f06fd2017-02-02 00:35:03 +01003354 { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },
Sebastian Hesselbarth6b358ae2014-10-22 20:26:44 +02003355 { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
Pali Rohár1fe976d2021-04-12 18:57:39 +02003356 { MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK },
3357 { MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK },
Marek Behúna978f7c2021-04-20 09:54:03 +02003358 { MARVELL_PHY_ID_88E6393_FAMILY, MARVELL_PHY_ID_MASK },
Maxim Kochetkova602ea82020-06-21 10:59:51 +03003359 { MARVELL_PHY_ID_88E1340S, MARVELL_PHY_ID_MASK },
Maxim Kochetkovf59babf2020-06-21 10:59:52 +03003360 { MARVELL_PHY_ID_88E1548P, MARVELL_PHY_ID_MASK },
David Woodhouse4e4f10f2010-04-02 01:05:56 +00003361 { }
3362};
3363
3364MODULE_DEVICE_TABLE(mdio, marvell_tbl);