1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Driver for the Texas Instruments DP83822, DP83825 and DP83826 PHYs.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2017 Texas Instruments Inc.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/ethtool.h>
8*4882a593Smuzhiyun #include <linux/etherdevice.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/mii.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/of.h>
13*4882a593Smuzhiyun #include <linux/phy.h>
14*4882a593Smuzhiyun #include <linux/netdevice.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define DP83822_PHY_ID 0x2000a240
17*4882a593Smuzhiyun #define DP83825S_PHY_ID 0x2000a140
18*4882a593Smuzhiyun #define DP83825I_PHY_ID 0x2000a150
19*4882a593Smuzhiyun #define DP83825CM_PHY_ID 0x2000a160
20*4882a593Smuzhiyun #define DP83825CS_PHY_ID 0x2000a170
21*4882a593Smuzhiyun #define DP83826C_PHY_ID 0x2000a130
22*4882a593Smuzhiyun #define DP83826NC_PHY_ID 0x2000a110
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define DP83822_DEVADDR 0x1f
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define MII_DP83822_CTRL_2 0x0a
27*4882a593Smuzhiyun #define MII_DP83822_PHYSTS 0x10
28*4882a593Smuzhiyun #define MII_DP83822_PHYSCR 0x11
29*4882a593Smuzhiyun #define MII_DP83822_MISR1 0x12
30*4882a593Smuzhiyun #define MII_DP83822_MISR2 0x13
31*4882a593Smuzhiyun #define MII_DP83822_FCSCR 0x14
32*4882a593Smuzhiyun #define MII_DP83822_RCSR 0x17
33*4882a593Smuzhiyun #define MII_DP83822_RESET_CTRL 0x1f
34*4882a593Smuzhiyun #define MII_DP83822_GENCFG 0x465
35*4882a593Smuzhiyun #define MII_DP83822_SOR1 0x467
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* GENCFG */
38*4882a593Smuzhiyun #define DP83822_SIG_DET_LOW BIT(0)
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* Control Register 2 bits */
41*4882a593Smuzhiyun #define DP83822_FX_ENABLE BIT(14)
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define DP83822_HW_RESET BIT(15)
44*4882a593Smuzhiyun #define DP83822_SW_RESET BIT(14)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* PHY STS bits */
47*4882a593Smuzhiyun #define DP83822_PHYSTS_DUPLEX BIT(2)
48*4882a593Smuzhiyun #define DP83822_PHYSTS_10 BIT(1)
49*4882a593Smuzhiyun #define DP83822_PHYSTS_LINK BIT(0)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* PHYSCR Register Fields */
52*4882a593Smuzhiyun #define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */
53*4882a593Smuzhiyun #define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* MISR1 bits */
56*4882a593Smuzhiyun #define DP83822_RX_ERR_HF_INT_EN BIT(0)
57*4882a593Smuzhiyun #define DP83822_FALSE_CARRIER_HF_INT_EN BIT(1)
58*4882a593Smuzhiyun #define DP83822_ANEG_COMPLETE_INT_EN BIT(2)
59*4882a593Smuzhiyun #define DP83822_DUP_MODE_CHANGE_INT_EN BIT(3)
60*4882a593Smuzhiyun #define DP83822_SPEED_CHANGED_INT_EN BIT(4)
61*4882a593Smuzhiyun #define DP83822_LINK_STAT_INT_EN BIT(5)
62*4882a593Smuzhiyun #define DP83822_ENERGY_DET_INT_EN BIT(6)
63*4882a593Smuzhiyun #define DP83822_LINK_QUAL_INT_EN BIT(7)
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* MISR2 bits */
66*4882a593Smuzhiyun #define DP83822_JABBER_DET_INT_EN BIT(0)
67*4882a593Smuzhiyun #define DP83822_WOL_PKT_INT_EN BIT(1)
68*4882a593Smuzhiyun #define DP83822_SLEEP_MODE_INT_EN BIT(2)
69*4882a593Smuzhiyun #define DP83822_MDI_XOVER_INT_EN BIT(3)
70*4882a593Smuzhiyun #define DP83822_LB_FIFO_INT_EN BIT(4)
71*4882a593Smuzhiyun #define DP83822_PAGE_RX_INT_EN BIT(5)
72*4882a593Smuzhiyun #define DP83822_ANEG_ERR_INT_EN BIT(6)
73*4882a593Smuzhiyun #define DP83822_EEE_ERROR_CHANGE_INT_EN BIT(7)
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* INT_STAT1 bits */
76*4882a593Smuzhiyun #define DP83822_WOL_INT_EN BIT(4)
77*4882a593Smuzhiyun #define DP83822_WOL_INT_STAT BIT(12)
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun #define MII_DP83822_RXSOP1 0x04a5
80*4882a593Smuzhiyun #define MII_DP83822_RXSOP2 0x04a6
81*4882a593Smuzhiyun #define MII_DP83822_RXSOP3 0x04a7
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* WoL Registers */
84*4882a593Smuzhiyun #define MII_DP83822_WOL_CFG 0x04a0
85*4882a593Smuzhiyun #define MII_DP83822_WOL_STAT 0x04a1
86*4882a593Smuzhiyun #define MII_DP83822_WOL_DA1 0x04a2
87*4882a593Smuzhiyun #define MII_DP83822_WOL_DA2 0x04a3
88*4882a593Smuzhiyun #define MII_DP83822_WOL_DA3 0x04a4
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* WoL bits */
91*4882a593Smuzhiyun #define DP83822_WOL_MAGIC_EN BIT(0)
92*4882a593Smuzhiyun #define DP83822_WOL_SECURE_ON BIT(5)
93*4882a593Smuzhiyun #define DP83822_WOL_EN BIT(7)
94*4882a593Smuzhiyun #define DP83822_WOL_INDICATION_SEL BIT(8)
95*4882a593Smuzhiyun #define DP83822_WOL_CLR_INDICATION BIT(11)
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /* RSCR bits */
98*4882a593Smuzhiyun #define DP83822_RX_CLK_SHIFT BIT(12)
99*4882a593Smuzhiyun #define DP83822_TX_CLK_SHIFT BIT(11)
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* SOR1 mode */
102*4882a593Smuzhiyun #define DP83822_STRAP_MODE1 0
103*4882a593Smuzhiyun #define DP83822_STRAP_MODE2 BIT(0)
104*4882a593Smuzhiyun #define DP83822_STRAP_MODE3 BIT(1)
105*4882a593Smuzhiyun #define DP83822_STRAP_MODE4 GENMASK(1, 0)
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun #define DP83822_COL_STRAP_MASK GENMASK(11, 10)
108*4882a593Smuzhiyun #define DP83822_COL_SHIFT 10
109*4882a593Smuzhiyun #define DP83822_RX_ER_STR_MASK GENMASK(9, 8)
110*4882a593Smuzhiyun #define DP83822_RX_ER_SHIFT 8
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun #define MII_DP83822_FIBER_ADVERTISE (ADVERTISED_TP | ADVERTISED_MII | \
113*4882a593Smuzhiyun ADVERTISED_FIBRE | \
114*4882a593Smuzhiyun ADVERTISED_Pause | ADVERTISED_Asym_Pause)
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun struct dp83822_private {
117*4882a593Smuzhiyun bool fx_signal_det_low;
118*4882a593Smuzhiyun int fx_enabled;
119*4882a593Smuzhiyun u16 fx_sd_enable;
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun
dp83822_ack_interrupt(struct phy_device * phydev)122*4882a593Smuzhiyun static int dp83822_ack_interrupt(struct phy_device *phydev)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun int err;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun err = phy_read(phydev, MII_DP83822_MISR1);
127*4882a593Smuzhiyun if (err < 0)
128*4882a593Smuzhiyun return err;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun err = phy_read(phydev, MII_DP83822_MISR2);
131*4882a593Smuzhiyun if (err < 0)
132*4882a593Smuzhiyun return err;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
dp83822_set_wol(struct phy_device * phydev,struct ethtool_wolinfo * wol)137*4882a593Smuzhiyun static int dp83822_set_wol(struct phy_device *phydev,
138*4882a593Smuzhiyun struct ethtool_wolinfo *wol)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct net_device *ndev = phydev->attached_dev;
141*4882a593Smuzhiyun u16 value;
142*4882a593Smuzhiyun const u8 *mac;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
145*4882a593Smuzhiyun mac = (const u8 *)ndev->dev_addr;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (!is_valid_ether_addr(mac))
148*4882a593Smuzhiyun return -EINVAL;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* MAC addresses start with byte 5, but stored in mac[0].
151*4882a593Smuzhiyun * 822 PHYs store bytes 4|5, 2|3, 0|1
152*4882a593Smuzhiyun */
153*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1,
154*4882a593Smuzhiyun (mac[1] << 8) | mac[0]);
155*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2,
156*4882a593Smuzhiyun (mac[3] << 8) | mac[2]);
157*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3,
158*4882a593Smuzhiyun (mac[5] << 8) | mac[4]);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun value = phy_read_mmd(phydev, DP83822_DEVADDR,
161*4882a593Smuzhiyun MII_DP83822_WOL_CFG);
162*4882a593Smuzhiyun if (wol->wolopts & WAKE_MAGIC)
163*4882a593Smuzhiyun value |= DP83822_WOL_MAGIC_EN;
164*4882a593Smuzhiyun else
165*4882a593Smuzhiyun value &= ~DP83822_WOL_MAGIC_EN;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (wol->wolopts & WAKE_MAGICSECURE) {
168*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR,
169*4882a593Smuzhiyun MII_DP83822_RXSOP1,
170*4882a593Smuzhiyun (wol->sopass[1] << 8) | wol->sopass[0]);
171*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR,
172*4882a593Smuzhiyun MII_DP83822_RXSOP2,
173*4882a593Smuzhiyun (wol->sopass[3] << 8) | wol->sopass[2]);
174*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR,
175*4882a593Smuzhiyun MII_DP83822_RXSOP3,
176*4882a593Smuzhiyun (wol->sopass[5] << 8) | wol->sopass[4]);
177*4882a593Smuzhiyun value |= DP83822_WOL_SECURE_ON;
178*4882a593Smuzhiyun } else {
179*4882a593Smuzhiyun value &= ~DP83822_WOL_SECURE_ON;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Clear any pending WoL interrupt */
183*4882a593Smuzhiyun phy_read(phydev, MII_DP83822_MISR2);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun value |= DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL |
186*4882a593Smuzhiyun DP83822_WOL_CLR_INDICATION;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun return phy_write_mmd(phydev, DP83822_DEVADDR,
189*4882a593Smuzhiyun MII_DP83822_WOL_CFG, value);
190*4882a593Smuzhiyun } else {
191*4882a593Smuzhiyun return phy_clear_bits_mmd(phydev, DP83822_DEVADDR,
192*4882a593Smuzhiyun MII_DP83822_WOL_CFG, DP83822_WOL_EN);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
dp83822_get_wol(struct phy_device * phydev,struct ethtool_wolinfo * wol)196*4882a593Smuzhiyun static void dp83822_get_wol(struct phy_device *phydev,
197*4882a593Smuzhiyun struct ethtool_wolinfo *wol)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun int value;
200*4882a593Smuzhiyun u16 sopass_val;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE);
203*4882a593Smuzhiyun wol->wolopts = 0;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (value & DP83822_WOL_MAGIC_EN)
208*4882a593Smuzhiyun wol->wolopts |= WAKE_MAGIC;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (value & DP83822_WOL_SECURE_ON) {
211*4882a593Smuzhiyun sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
212*4882a593Smuzhiyun MII_DP83822_RXSOP1);
213*4882a593Smuzhiyun wol->sopass[0] = (sopass_val & 0xff);
214*4882a593Smuzhiyun wol->sopass[1] = (sopass_val >> 8);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
217*4882a593Smuzhiyun MII_DP83822_RXSOP2);
218*4882a593Smuzhiyun wol->sopass[2] = (sopass_val & 0xff);
219*4882a593Smuzhiyun wol->sopass[3] = (sopass_val >> 8);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
222*4882a593Smuzhiyun MII_DP83822_RXSOP3);
223*4882a593Smuzhiyun wol->sopass[4] = (sopass_val & 0xff);
224*4882a593Smuzhiyun wol->sopass[5] = (sopass_val >> 8);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun wol->wolopts |= WAKE_MAGICSECURE;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* WoL is not enabled so set wolopts to 0 */
230*4882a593Smuzhiyun if (!(value & DP83822_WOL_EN))
231*4882a593Smuzhiyun wol->wolopts = 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
dp83822_config_intr(struct phy_device * phydev)234*4882a593Smuzhiyun static int dp83822_config_intr(struct phy_device *phydev)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct dp83822_private *dp83822 = phydev->priv;
237*4882a593Smuzhiyun int misr_status;
238*4882a593Smuzhiyun int physcr_status;
239*4882a593Smuzhiyun int err;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
242*4882a593Smuzhiyun misr_status = phy_read(phydev, MII_DP83822_MISR1);
243*4882a593Smuzhiyun if (misr_status < 0)
244*4882a593Smuzhiyun return misr_status;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun misr_status |= (DP83822_LINK_STAT_INT_EN |
247*4882a593Smuzhiyun DP83822_ENERGY_DET_INT_EN |
248*4882a593Smuzhiyun DP83822_LINK_QUAL_INT_EN);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun if (!dp83822->fx_enabled)
251*4882a593Smuzhiyun misr_status |= DP83822_ANEG_COMPLETE_INT_EN |
252*4882a593Smuzhiyun DP83822_DUP_MODE_CHANGE_INT_EN |
253*4882a593Smuzhiyun DP83822_SPEED_CHANGED_INT_EN;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun err = phy_write(phydev, MII_DP83822_MISR1, misr_status);
257*4882a593Smuzhiyun if (err < 0)
258*4882a593Smuzhiyun return err;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun misr_status = phy_read(phydev, MII_DP83822_MISR2);
261*4882a593Smuzhiyun if (misr_status < 0)
262*4882a593Smuzhiyun return misr_status;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun misr_status |= (DP83822_JABBER_DET_INT_EN |
265*4882a593Smuzhiyun DP83822_SLEEP_MODE_INT_EN |
266*4882a593Smuzhiyun DP83822_LB_FIFO_INT_EN |
267*4882a593Smuzhiyun DP83822_PAGE_RX_INT_EN |
268*4882a593Smuzhiyun DP83822_EEE_ERROR_CHANGE_INT_EN);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (!dp83822->fx_enabled)
271*4882a593Smuzhiyun misr_status |= DP83822_ANEG_ERR_INT_EN |
272*4882a593Smuzhiyun DP83822_WOL_PKT_INT_EN;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun err = phy_write(phydev, MII_DP83822_MISR2, misr_status);
275*4882a593Smuzhiyun if (err < 0)
276*4882a593Smuzhiyun return err;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);
279*4882a593Smuzhiyun if (physcr_status < 0)
280*4882a593Smuzhiyun return physcr_status;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun } else {
285*4882a593Smuzhiyun err = phy_write(phydev, MII_DP83822_MISR1, 0);
286*4882a593Smuzhiyun if (err < 0)
287*4882a593Smuzhiyun return err;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun err = phy_write(phydev, MII_DP83822_MISR2, 0);
290*4882a593Smuzhiyun if (err < 0)
291*4882a593Smuzhiyun return err;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);
294*4882a593Smuzhiyun if (physcr_status < 0)
295*4882a593Smuzhiyun return physcr_status;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun physcr_status &= ~DP83822_PHYSCR_INTEN;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
dp8382x_disable_wol(struct phy_device * phydev)303*4882a593Smuzhiyun static int dp8382x_disable_wol(struct phy_device *phydev)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun return phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG,
306*4882a593Smuzhiyun DP83822_WOL_EN | DP83822_WOL_MAGIC_EN |
307*4882a593Smuzhiyun DP83822_WOL_SECURE_ON);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
dp83822_read_status(struct phy_device * phydev)310*4882a593Smuzhiyun static int dp83822_read_status(struct phy_device *phydev)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun struct dp83822_private *dp83822 = phydev->priv;
313*4882a593Smuzhiyun int status = phy_read(phydev, MII_DP83822_PHYSTS);
314*4882a593Smuzhiyun int ctrl2;
315*4882a593Smuzhiyun int ret;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun if (dp83822->fx_enabled) {
318*4882a593Smuzhiyun if (status & DP83822_PHYSTS_LINK) {
319*4882a593Smuzhiyun phydev->speed = SPEED_UNKNOWN;
320*4882a593Smuzhiyun phydev->duplex = DUPLEX_UNKNOWN;
321*4882a593Smuzhiyun } else {
322*4882a593Smuzhiyun ctrl2 = phy_read(phydev, MII_DP83822_CTRL_2);
323*4882a593Smuzhiyun if (ctrl2 < 0)
324*4882a593Smuzhiyun return ctrl2;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun if (!(ctrl2 & DP83822_FX_ENABLE)) {
327*4882a593Smuzhiyun ret = phy_write(phydev, MII_DP83822_CTRL_2,
328*4882a593Smuzhiyun DP83822_FX_ENABLE | ctrl2);
329*4882a593Smuzhiyun if (ret < 0)
330*4882a593Smuzhiyun return ret;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun ret = genphy_read_status(phydev);
336*4882a593Smuzhiyun if (ret)
337*4882a593Smuzhiyun return ret;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (status < 0)
340*4882a593Smuzhiyun return status;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (status & DP83822_PHYSTS_DUPLEX)
343*4882a593Smuzhiyun phydev->duplex = DUPLEX_FULL;
344*4882a593Smuzhiyun else
345*4882a593Smuzhiyun phydev->duplex = DUPLEX_HALF;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (status & DP83822_PHYSTS_10)
348*4882a593Smuzhiyun phydev->speed = SPEED_10;
349*4882a593Smuzhiyun else
350*4882a593Smuzhiyun phydev->speed = SPEED_100;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun return 0;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
dp83822_config_init(struct phy_device * phydev)355*4882a593Smuzhiyun static int dp83822_config_init(struct phy_device *phydev)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun struct dp83822_private *dp83822 = phydev->priv;
358*4882a593Smuzhiyun struct device *dev = &phydev->mdio.dev;
359*4882a593Smuzhiyun int rgmii_delay;
360*4882a593Smuzhiyun s32 rx_int_delay;
361*4882a593Smuzhiyun s32 tx_int_delay;
362*4882a593Smuzhiyun int err = 0;
363*4882a593Smuzhiyun int bmcr;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun if (phy_interface_is_rgmii(phydev)) {
366*4882a593Smuzhiyun rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
367*4882a593Smuzhiyun true);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (rx_int_delay <= 0)
370*4882a593Smuzhiyun rgmii_delay = 0;
371*4882a593Smuzhiyun else
372*4882a593Smuzhiyun rgmii_delay = DP83822_RX_CLK_SHIFT;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
375*4882a593Smuzhiyun false);
376*4882a593Smuzhiyun if (tx_int_delay <= 0)
377*4882a593Smuzhiyun rgmii_delay &= ~DP83822_TX_CLK_SHIFT;
378*4882a593Smuzhiyun else
379*4882a593Smuzhiyun rgmii_delay |= DP83822_TX_CLK_SHIFT;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (rgmii_delay) {
382*4882a593Smuzhiyun err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
383*4882a593Smuzhiyun MII_DP83822_RCSR, rgmii_delay);
384*4882a593Smuzhiyun if (err)
385*4882a593Smuzhiyun return err;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (dp83822->fx_enabled) {
390*4882a593Smuzhiyun err = phy_modify(phydev, MII_DP83822_CTRL_2,
391*4882a593Smuzhiyun DP83822_FX_ENABLE, 1);
392*4882a593Smuzhiyun if (err < 0)
393*4882a593Smuzhiyun return err;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun /* Only allow advertising what this PHY supports */
396*4882a593Smuzhiyun linkmode_and(phydev->advertising, phydev->advertising,
397*4882a593Smuzhiyun phydev->supported);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
400*4882a593Smuzhiyun phydev->supported);
401*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
402*4882a593Smuzhiyun phydev->advertising);
403*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
404*4882a593Smuzhiyun phydev->supported);
405*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
406*4882a593Smuzhiyun phydev->supported);
407*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
408*4882a593Smuzhiyun phydev->advertising);
409*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
410*4882a593Smuzhiyun phydev->advertising);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* Auto neg is not supported in fiber mode */
413*4882a593Smuzhiyun bmcr = phy_read(phydev, MII_BMCR);
414*4882a593Smuzhiyun if (bmcr < 0)
415*4882a593Smuzhiyun return bmcr;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (bmcr & BMCR_ANENABLE) {
418*4882a593Smuzhiyun err = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
419*4882a593Smuzhiyun if (err < 0)
420*4882a593Smuzhiyun return err;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun phydev->autoneg = AUTONEG_DISABLE;
423*4882a593Smuzhiyun linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
424*4882a593Smuzhiyun phydev->supported);
425*4882a593Smuzhiyun linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
426*4882a593Smuzhiyun phydev->advertising);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* Setup fiber advertisement */
429*4882a593Smuzhiyun err = phy_modify_changed(phydev, MII_ADVERTISE,
430*4882a593Smuzhiyun MII_DP83822_FIBER_ADVERTISE,
431*4882a593Smuzhiyun MII_DP83822_FIBER_ADVERTISE);
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun if (err < 0)
434*4882a593Smuzhiyun return err;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (dp83822->fx_signal_det_low) {
437*4882a593Smuzhiyun err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
438*4882a593Smuzhiyun MII_DP83822_GENCFG,
439*4882a593Smuzhiyun DP83822_SIG_DET_LOW);
440*4882a593Smuzhiyun if (err)
441*4882a593Smuzhiyun return err;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun return dp8382x_disable_wol(phydev);
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
dp8382x_config_init(struct phy_device * phydev)447*4882a593Smuzhiyun static int dp8382x_config_init(struct phy_device *phydev)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun return dp8382x_disable_wol(phydev);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
dp83822_phy_reset(struct phy_device * phydev)452*4882a593Smuzhiyun static int dp83822_phy_reset(struct phy_device *phydev)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun int err;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_SW_RESET);
457*4882a593Smuzhiyun if (err < 0)
458*4882a593Smuzhiyun return err;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return phydev->drv->config_init(phydev);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun #ifdef CONFIG_OF_MDIO
dp83822_of_init(struct phy_device * phydev)464*4882a593Smuzhiyun static int dp83822_of_init(struct phy_device *phydev)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun struct dp83822_private *dp83822 = phydev->priv;
467*4882a593Smuzhiyun struct device *dev = &phydev->mdio.dev;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* Signal detection for the PHY is only enabled if the FX_EN and the
470*4882a593Smuzhiyun * SD_EN pins are strapped. Signal detection can only enabled if FX_EN
471*4882a593Smuzhiyun * is strapped otherwise signal detection is disabled for the PHY.
472*4882a593Smuzhiyun */
473*4882a593Smuzhiyun if (dp83822->fx_enabled && dp83822->fx_sd_enable)
474*4882a593Smuzhiyun dp83822->fx_signal_det_low = device_property_present(dev,
475*4882a593Smuzhiyun "ti,link-loss-low");
476*4882a593Smuzhiyun if (!dp83822->fx_enabled)
477*4882a593Smuzhiyun dp83822->fx_enabled = device_property_present(dev,
478*4882a593Smuzhiyun "ti,fiber-mode");
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun #else
dp83822_of_init(struct phy_device * phydev)483*4882a593Smuzhiyun static int dp83822_of_init(struct phy_device *phydev)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun return 0;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun #endif /* CONFIG_OF_MDIO */
488*4882a593Smuzhiyun
dp83822_read_straps(struct phy_device * phydev)489*4882a593Smuzhiyun static int dp83822_read_straps(struct phy_device *phydev)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun struct dp83822_private *dp83822 = phydev->priv;
492*4882a593Smuzhiyun int fx_enabled, fx_sd_enable;
493*4882a593Smuzhiyun int val;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun val = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_SOR1);
496*4882a593Smuzhiyun if (val < 0)
497*4882a593Smuzhiyun return val;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun fx_enabled = (val & DP83822_COL_STRAP_MASK) >> DP83822_COL_SHIFT;
500*4882a593Smuzhiyun if (fx_enabled == DP83822_STRAP_MODE2 ||
501*4882a593Smuzhiyun fx_enabled == DP83822_STRAP_MODE3)
502*4882a593Smuzhiyun dp83822->fx_enabled = 1;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun if (dp83822->fx_enabled) {
505*4882a593Smuzhiyun fx_sd_enable = (val & DP83822_RX_ER_STR_MASK) >> DP83822_RX_ER_SHIFT;
506*4882a593Smuzhiyun if (fx_sd_enable == DP83822_STRAP_MODE3 ||
507*4882a593Smuzhiyun fx_sd_enable == DP83822_STRAP_MODE4)
508*4882a593Smuzhiyun dp83822->fx_sd_enable = 1;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun return 0;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
dp83822_probe(struct phy_device * phydev)514*4882a593Smuzhiyun static int dp83822_probe(struct phy_device *phydev)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun struct dp83822_private *dp83822;
517*4882a593Smuzhiyun int ret;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822),
520*4882a593Smuzhiyun GFP_KERNEL);
521*4882a593Smuzhiyun if (!dp83822)
522*4882a593Smuzhiyun return -ENOMEM;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun phydev->priv = dp83822;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun ret = dp83822_read_straps(phydev);
527*4882a593Smuzhiyun if (ret)
528*4882a593Smuzhiyun return ret;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun dp83822_of_init(phydev);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun if (dp83822->fx_enabled)
533*4882a593Smuzhiyun phydev->port = PORT_FIBRE;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun return 0;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
dp83822_suspend(struct phy_device * phydev)538*4882a593Smuzhiyun static int dp83822_suspend(struct phy_device *phydev)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun int value;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (!(value & DP83822_WOL_EN))
545*4882a593Smuzhiyun genphy_suspend(phydev);
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun return 0;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
dp83822_resume(struct phy_device * phydev)550*4882a593Smuzhiyun static int dp83822_resume(struct phy_device *phydev)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun int value;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun genphy_resume(phydev);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value |
559*4882a593Smuzhiyun DP83822_WOL_CLR_INDICATION);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun return 0;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun #define DP83822_PHY_DRIVER(_id, _name) \
565*4882a593Smuzhiyun { \
566*4882a593Smuzhiyun PHY_ID_MATCH_MODEL(_id), \
567*4882a593Smuzhiyun .name = (_name), \
568*4882a593Smuzhiyun /* PHY_BASIC_FEATURES */ \
569*4882a593Smuzhiyun .probe = dp83822_probe, \
570*4882a593Smuzhiyun .soft_reset = dp83822_phy_reset, \
571*4882a593Smuzhiyun .config_init = dp83822_config_init, \
572*4882a593Smuzhiyun .read_status = dp83822_read_status, \
573*4882a593Smuzhiyun .get_wol = dp83822_get_wol, \
574*4882a593Smuzhiyun .set_wol = dp83822_set_wol, \
575*4882a593Smuzhiyun .ack_interrupt = dp83822_ack_interrupt, \
576*4882a593Smuzhiyun .config_intr = dp83822_config_intr, \
577*4882a593Smuzhiyun .suspend = dp83822_suspend, \
578*4882a593Smuzhiyun .resume = dp83822_resume, \
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun #define DP8382X_PHY_DRIVER(_id, _name) \
582*4882a593Smuzhiyun { \
583*4882a593Smuzhiyun PHY_ID_MATCH_MODEL(_id), \
584*4882a593Smuzhiyun .name = (_name), \
585*4882a593Smuzhiyun /* PHY_BASIC_FEATURES */ \
586*4882a593Smuzhiyun .soft_reset = dp83822_phy_reset, \
587*4882a593Smuzhiyun .config_init = dp8382x_config_init, \
588*4882a593Smuzhiyun .get_wol = dp83822_get_wol, \
589*4882a593Smuzhiyun .set_wol = dp83822_set_wol, \
590*4882a593Smuzhiyun .ack_interrupt = dp83822_ack_interrupt, \
591*4882a593Smuzhiyun .config_intr = dp83822_config_intr, \
592*4882a593Smuzhiyun .suspend = dp83822_suspend, \
593*4882a593Smuzhiyun .resume = dp83822_resume, \
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun static struct phy_driver dp83822_driver[] = {
597*4882a593Smuzhiyun DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"),
598*4882a593Smuzhiyun DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"),
599*4882a593Smuzhiyun DP8382X_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"),
600*4882a593Smuzhiyun DP8382X_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"),
601*4882a593Smuzhiyun DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"),
602*4882a593Smuzhiyun DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"),
603*4882a593Smuzhiyun DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"),
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun module_phy_driver(dp83822_driver);
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun static struct mdio_device_id __maybe_unused dp83822_tbl[] = {
608*4882a593Smuzhiyun { DP83822_PHY_ID, 0xfffffff0 },
609*4882a593Smuzhiyun { DP83825I_PHY_ID, 0xfffffff0 },
610*4882a593Smuzhiyun { DP83826C_PHY_ID, 0xfffffff0 },
611*4882a593Smuzhiyun { DP83826NC_PHY_ID, 0xfffffff0 },
612*4882a593Smuzhiyun { DP83825S_PHY_ID, 0xfffffff0 },
613*4882a593Smuzhiyun { DP83825CM_PHY_ID, 0xfffffff0 },
614*4882a593Smuzhiyun { DP83825CS_PHY_ID, 0xfffffff0 },
615*4882a593Smuzhiyun { },
616*4882a593Smuzhiyun };
617*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mdio, dp83822_tbl);
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver");
620*4882a593Smuzhiyun MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
621*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
622