xref: /OK3568_Linux_fs/kernel/drivers/net/phy/dp83867.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Driver for the Texas Instruments DP83867 PHY
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2015 Texas Instruments Inc.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/ethtool.h>
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/mii.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/phy.h>
13*4882a593Smuzhiyun #include <linux/delay.h>
14*4882a593Smuzhiyun #include <linux/netdevice.h>
15*4882a593Smuzhiyun #include <linux/etherdevice.h>
16*4882a593Smuzhiyun #include <linux/bitfield.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <dt-bindings/net/ti-dp83867.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define DP83867_PHY_ID		0x2000a231
21*4882a593Smuzhiyun #define DP83867_DEVADDR		0x1f
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define MII_DP83867_PHYCTRL	0x10
24*4882a593Smuzhiyun #define MII_DP83867_PHYSTS	0x11
25*4882a593Smuzhiyun #define MII_DP83867_MICR	0x12
26*4882a593Smuzhiyun #define MII_DP83867_ISR		0x13
27*4882a593Smuzhiyun #define DP83867_CFG2		0x14
28*4882a593Smuzhiyun #define DP83867_CFG3		0x1e
29*4882a593Smuzhiyun #define DP83867_CTRL		0x1f
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* Extended Registers */
32*4882a593Smuzhiyun #define DP83867_FLD_THR_CFG	0x002e
33*4882a593Smuzhiyun #define DP83867_CFG4		0x0031
34*4882a593Smuzhiyun #define DP83867_CFG4_SGMII_ANEG_MASK (BIT(5) | BIT(6))
35*4882a593Smuzhiyun #define DP83867_CFG4_SGMII_ANEG_TIMER_11MS   (3 << 5)
36*4882a593Smuzhiyun #define DP83867_CFG4_SGMII_ANEG_TIMER_800US  (2 << 5)
37*4882a593Smuzhiyun #define DP83867_CFG4_SGMII_ANEG_TIMER_2US    (1 << 5)
38*4882a593Smuzhiyun #define DP83867_CFG4_SGMII_ANEG_TIMER_16MS   (0 << 5)
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define DP83867_RGMIICTL	0x0032
41*4882a593Smuzhiyun #define DP83867_STRAP_STS1	0x006E
42*4882a593Smuzhiyun #define DP83867_STRAP_STS2	0x006f
43*4882a593Smuzhiyun #define DP83867_RGMIIDCTL	0x0086
44*4882a593Smuzhiyun #define DP83867_RXFCFG		0x0134
45*4882a593Smuzhiyun #define DP83867_RXFPMD1	0x0136
46*4882a593Smuzhiyun #define DP83867_RXFPMD2	0x0137
47*4882a593Smuzhiyun #define DP83867_RXFPMD3	0x0138
48*4882a593Smuzhiyun #define DP83867_RXFSOP1	0x0139
49*4882a593Smuzhiyun #define DP83867_RXFSOP2	0x013A
50*4882a593Smuzhiyun #define DP83867_RXFSOP3	0x013B
51*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG	0x0170
52*4882a593Smuzhiyun #define DP83867_SGMIICTL	0x00D3
53*4882a593Smuzhiyun #define DP83867_10M_SGMII_CFG   0x016F
54*4882a593Smuzhiyun #define DP83867_10M_SGMII_RATE_ADAPT_MASK BIT(7)
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define DP83867_SW_RESET	BIT(15)
57*4882a593Smuzhiyun #define DP83867_SW_RESTART	BIT(14)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* MICR Interrupt bits */
60*4882a593Smuzhiyun #define MII_DP83867_MICR_AN_ERR_INT_EN		BIT(15)
61*4882a593Smuzhiyun #define MII_DP83867_MICR_SPEED_CHNG_INT_EN	BIT(14)
62*4882a593Smuzhiyun #define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN	BIT(13)
63*4882a593Smuzhiyun #define MII_DP83867_MICR_PAGE_RXD_INT_EN	BIT(12)
64*4882a593Smuzhiyun #define MII_DP83867_MICR_AUTONEG_COMP_INT_EN	BIT(11)
65*4882a593Smuzhiyun #define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN	BIT(10)
66*4882a593Smuzhiyun #define MII_DP83867_MICR_FALSE_CARRIER_INT_EN	BIT(8)
67*4882a593Smuzhiyun #define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN	BIT(4)
68*4882a593Smuzhiyun #define MII_DP83867_MICR_WOL_INT_EN		BIT(3)
69*4882a593Smuzhiyun #define MII_DP83867_MICR_XGMII_ERR_INT_EN	BIT(2)
70*4882a593Smuzhiyun #define MII_DP83867_MICR_POL_CHNG_INT_EN	BIT(1)
71*4882a593Smuzhiyun #define MII_DP83867_MICR_JABBER_INT_EN		BIT(0)
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /* RGMIICTL bits */
74*4882a593Smuzhiyun #define DP83867_RGMII_TX_CLK_DELAY_EN		BIT(1)
75*4882a593Smuzhiyun #define DP83867_RGMII_RX_CLK_DELAY_EN		BIT(0)
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* SGMIICTL bits */
78*4882a593Smuzhiyun #define DP83867_SGMII_TYPE		BIT(14)
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /* RXFCFG bits*/
81*4882a593Smuzhiyun #define DP83867_WOL_MAGIC_EN		BIT(0)
82*4882a593Smuzhiyun #define DP83867_WOL_BCAST_EN		BIT(2)
83*4882a593Smuzhiyun #define DP83867_WOL_UCAST_EN		BIT(4)
84*4882a593Smuzhiyun #define DP83867_WOL_SEC_EN		BIT(5)
85*4882a593Smuzhiyun #define DP83867_WOL_ENH_MAC		BIT(7)
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /* STRAP_STS1 bits */
88*4882a593Smuzhiyun #define DP83867_STRAP_STS1_RESERVED		BIT(11)
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /* STRAP_STS2 bits */
91*4882a593Smuzhiyun #define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK	GENMASK(6, 4)
92*4882a593Smuzhiyun #define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT	4
93*4882a593Smuzhiyun #define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK	GENMASK(2, 0)
94*4882a593Smuzhiyun #define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT	0
95*4882a593Smuzhiyun #define DP83867_STRAP_STS2_CLK_SKEW_NONE	BIT(2)
96*4882a593Smuzhiyun #define DP83867_STRAP_STS2_STRAP_FLD		BIT(10)
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /* PHY CTRL bits */
99*4882a593Smuzhiyun #define DP83867_PHYCR_TX_FIFO_DEPTH_SHIFT	14
100*4882a593Smuzhiyun #define DP83867_PHYCR_RX_FIFO_DEPTH_SHIFT	12
101*4882a593Smuzhiyun #define DP83867_PHYCR_FIFO_DEPTH_MAX		0x03
102*4882a593Smuzhiyun #define DP83867_PHYCR_TX_FIFO_DEPTH_MASK	GENMASK(15, 14)
103*4882a593Smuzhiyun #define DP83867_PHYCR_RX_FIFO_DEPTH_MASK	GENMASK(13, 12)
104*4882a593Smuzhiyun #define DP83867_PHYCR_RESERVED_MASK		BIT(11)
105*4882a593Smuzhiyun #define DP83867_PHYCR_FORCE_LINK_GOOD		BIT(10)
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /* RGMIIDCTL bits */
108*4882a593Smuzhiyun #define DP83867_RGMII_TX_CLK_DELAY_MAX		0xf
109*4882a593Smuzhiyun #define DP83867_RGMII_TX_CLK_DELAY_SHIFT	4
110*4882a593Smuzhiyun #define DP83867_RGMII_TX_CLK_DELAY_INV	(DP83867_RGMII_TX_CLK_DELAY_MAX + 1)
111*4882a593Smuzhiyun #define DP83867_RGMII_RX_CLK_DELAY_MAX		0xf
112*4882a593Smuzhiyun #define DP83867_RGMII_RX_CLK_DELAY_SHIFT	0
113*4882a593Smuzhiyun #define DP83867_RGMII_RX_CLK_DELAY_INV	(DP83867_RGMII_RX_CLK_DELAY_MAX + 1)
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /* IO_MUX_CFG bits */
116*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK	0x1f
117*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX	0x0
118*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN	0x1f
119*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG_CLK_O_DISABLE	BIT(6)
120*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK	(0x1f << 8)
121*4882a593Smuzhiyun #define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT	8
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun /* PHY STS bits */
124*4882a593Smuzhiyun #define DP83867_PHYSTS_1000			BIT(15)
125*4882a593Smuzhiyun #define DP83867_PHYSTS_100			BIT(14)
126*4882a593Smuzhiyun #define DP83867_PHYSTS_DUPLEX			BIT(13)
127*4882a593Smuzhiyun #define DP83867_PHYSTS_LINK			BIT(10)
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /* CFG2 bits */
130*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_EN		(BIT(8) | BIT(9))
131*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_ATTEMPT_MASK	(BIT(10) | BIT(11))
132*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_1_COUNT_VAL	0
133*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_2_COUNT_VAL	1
134*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_4_COUNT_VAL	2
135*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_8_COUNT_VAL	3
136*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_1_COUNT	1
137*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_2_COUNT	2
138*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_4_COUNT	4
139*4882a593Smuzhiyun #define DP83867_DOWNSHIFT_8_COUNT	8
140*4882a593Smuzhiyun #define DP83867_SGMII_AUTONEG_EN	BIT(7)
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun /* CFG3 bits */
143*4882a593Smuzhiyun #define DP83867_CFG3_INT_OE			BIT(7)
144*4882a593Smuzhiyun #define DP83867_CFG3_ROBUST_AUTO_MDIX		BIT(9)
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /* CFG4 bits */
147*4882a593Smuzhiyun #define DP83867_CFG4_PORT_MIRROR_EN              BIT(0)
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun /* FLD_THR_CFG */
150*4882a593Smuzhiyun #define DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK	0x7
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun enum {
153*4882a593Smuzhiyun 	DP83867_PORT_MIRROING_KEEP,
154*4882a593Smuzhiyun 	DP83867_PORT_MIRROING_EN,
155*4882a593Smuzhiyun 	DP83867_PORT_MIRROING_DIS,
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun struct dp83867_private {
159*4882a593Smuzhiyun 	u32 rx_id_delay;
160*4882a593Smuzhiyun 	u32 tx_id_delay;
161*4882a593Smuzhiyun 	u32 tx_fifo_depth;
162*4882a593Smuzhiyun 	u32 rx_fifo_depth;
163*4882a593Smuzhiyun 	int io_impedance;
164*4882a593Smuzhiyun 	int port_mirroring;
165*4882a593Smuzhiyun 	bool rxctrl_strap_quirk;
166*4882a593Smuzhiyun 	bool set_clk_output;
167*4882a593Smuzhiyun 	u32 clk_output_sel;
168*4882a593Smuzhiyun 	bool sgmii_ref_clk_en;
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun 
dp83867_ack_interrupt(struct phy_device * phydev)171*4882a593Smuzhiyun static int dp83867_ack_interrupt(struct phy_device *phydev)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	int err = phy_read(phydev, MII_DP83867_ISR);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (err < 0)
176*4882a593Smuzhiyun 		return err;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
dp83867_set_wol(struct phy_device * phydev,struct ethtool_wolinfo * wol)181*4882a593Smuzhiyun static int dp83867_set_wol(struct phy_device *phydev,
182*4882a593Smuzhiyun 			   struct ethtool_wolinfo *wol)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	struct net_device *ndev = phydev->attached_dev;
185*4882a593Smuzhiyun 	u16 val_rxcfg, val_micr;
186*4882a593Smuzhiyun 	u8 *mac;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	val_rxcfg = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG);
189*4882a593Smuzhiyun 	val_micr = phy_read(phydev, MII_DP83867_MICR);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_UCAST |
192*4882a593Smuzhiyun 			    WAKE_BCAST)) {
193*4882a593Smuzhiyun 		val_rxcfg |= DP83867_WOL_ENH_MAC;
194*4882a593Smuzhiyun 		val_micr |= MII_DP83867_MICR_WOL_INT_EN;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 		if (wol->wolopts & WAKE_MAGIC) {
197*4882a593Smuzhiyun 			mac = (u8 *)ndev->dev_addr;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 			if (!is_valid_ether_addr(mac))
200*4882a593Smuzhiyun 				return -EINVAL;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD1,
203*4882a593Smuzhiyun 				      (mac[1] << 8 | mac[0]));
204*4882a593Smuzhiyun 			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD2,
205*4882a593Smuzhiyun 				      (mac[3] << 8 | mac[2]));
206*4882a593Smuzhiyun 			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD3,
207*4882a593Smuzhiyun 				      (mac[5] << 8 | mac[4]));
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 			val_rxcfg |= DP83867_WOL_MAGIC_EN;
210*4882a593Smuzhiyun 		} else {
211*4882a593Smuzhiyun 			val_rxcfg &= ~DP83867_WOL_MAGIC_EN;
212*4882a593Smuzhiyun 		}
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		if (wol->wolopts & WAKE_MAGICSECURE) {
215*4882a593Smuzhiyun 			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1,
216*4882a593Smuzhiyun 				      (wol->sopass[1] << 8) | wol->sopass[0]);
217*4882a593Smuzhiyun 			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP2,
218*4882a593Smuzhiyun 				      (wol->sopass[3] << 8) | wol->sopass[2]);
219*4882a593Smuzhiyun 			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP3,
220*4882a593Smuzhiyun 				      (wol->sopass[5] << 8) | wol->sopass[4]);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 			val_rxcfg |= DP83867_WOL_SEC_EN;
223*4882a593Smuzhiyun 		} else {
224*4882a593Smuzhiyun 			val_rxcfg &= ~DP83867_WOL_SEC_EN;
225*4882a593Smuzhiyun 		}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 		if (wol->wolopts & WAKE_UCAST)
228*4882a593Smuzhiyun 			val_rxcfg |= DP83867_WOL_UCAST_EN;
229*4882a593Smuzhiyun 		else
230*4882a593Smuzhiyun 			val_rxcfg &= ~DP83867_WOL_UCAST_EN;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		if (wol->wolopts & WAKE_BCAST)
233*4882a593Smuzhiyun 			val_rxcfg |= DP83867_WOL_BCAST_EN;
234*4882a593Smuzhiyun 		else
235*4882a593Smuzhiyun 			val_rxcfg &= ~DP83867_WOL_BCAST_EN;
236*4882a593Smuzhiyun 	} else {
237*4882a593Smuzhiyun 		val_rxcfg &= ~DP83867_WOL_ENH_MAC;
238*4882a593Smuzhiyun 		val_micr &= ~MII_DP83867_MICR_WOL_INT_EN;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG, val_rxcfg);
242*4882a593Smuzhiyun 	phy_write(phydev, MII_DP83867_MICR, val_micr);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
dp83867_get_wol(struct phy_device * phydev,struct ethtool_wolinfo * wol)247*4882a593Smuzhiyun static void dp83867_get_wol(struct phy_device *phydev,
248*4882a593Smuzhiyun 			    struct ethtool_wolinfo *wol)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	u16 value, sopass_val;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC |
253*4882a593Smuzhiyun 			WAKE_MAGICSECURE);
254*4882a593Smuzhiyun 	wol->wolopts = 0;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	value = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (value & DP83867_WOL_UCAST_EN)
259*4882a593Smuzhiyun 		wol->wolopts |= WAKE_UCAST;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (value & DP83867_WOL_BCAST_EN)
262*4882a593Smuzhiyun 		wol->wolopts |= WAKE_BCAST;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (value & DP83867_WOL_MAGIC_EN)
265*4882a593Smuzhiyun 		wol->wolopts |= WAKE_MAGIC;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (value & DP83867_WOL_SEC_EN) {
268*4882a593Smuzhiyun 		sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR,
269*4882a593Smuzhiyun 					  DP83867_RXFSOP1);
270*4882a593Smuzhiyun 		wol->sopass[0] = (sopass_val & 0xff);
271*4882a593Smuzhiyun 		wol->sopass[1] = (sopass_val >> 8);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 		sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR,
274*4882a593Smuzhiyun 					  DP83867_RXFSOP2);
275*4882a593Smuzhiyun 		wol->sopass[2] = (sopass_val & 0xff);
276*4882a593Smuzhiyun 		wol->sopass[3] = (sopass_val >> 8);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR,
279*4882a593Smuzhiyun 					  DP83867_RXFSOP3);
280*4882a593Smuzhiyun 		wol->sopass[4] = (sopass_val & 0xff);
281*4882a593Smuzhiyun 		wol->sopass[5] = (sopass_val >> 8);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		wol->wolopts |= WAKE_MAGICSECURE;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (!(value & DP83867_WOL_ENH_MAC))
287*4882a593Smuzhiyun 		wol->wolopts = 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
dp83867_config_intr(struct phy_device * phydev)290*4882a593Smuzhiyun static int dp83867_config_intr(struct phy_device *phydev)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	int micr_status;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
295*4882a593Smuzhiyun 		micr_status = phy_read(phydev, MII_DP83867_MICR);
296*4882a593Smuzhiyun 		if (micr_status < 0)
297*4882a593Smuzhiyun 			return micr_status;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 		micr_status |=
300*4882a593Smuzhiyun 			(MII_DP83867_MICR_AN_ERR_INT_EN |
301*4882a593Smuzhiyun 			MII_DP83867_MICR_SPEED_CHNG_INT_EN |
302*4882a593Smuzhiyun 			MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
303*4882a593Smuzhiyun 			MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
304*4882a593Smuzhiyun 			MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
305*4882a593Smuzhiyun 			MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		return phy_write(phydev, MII_DP83867_MICR, micr_status);
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	micr_status = 0x0;
311*4882a593Smuzhiyun 	return phy_write(phydev, MII_DP83867_MICR, micr_status);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
dp83867_read_status(struct phy_device * phydev)314*4882a593Smuzhiyun static int dp83867_read_status(struct phy_device *phydev)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	int status = phy_read(phydev, MII_DP83867_PHYSTS);
317*4882a593Smuzhiyun 	int ret;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	ret = genphy_read_status(phydev);
320*4882a593Smuzhiyun 	if (ret)
321*4882a593Smuzhiyun 		return ret;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (status < 0)
324*4882a593Smuzhiyun 		return status;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if (status & DP83867_PHYSTS_DUPLEX)
327*4882a593Smuzhiyun 		phydev->duplex = DUPLEX_FULL;
328*4882a593Smuzhiyun 	else
329*4882a593Smuzhiyun 		phydev->duplex = DUPLEX_HALF;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	if (status & DP83867_PHYSTS_1000)
332*4882a593Smuzhiyun 		phydev->speed = SPEED_1000;
333*4882a593Smuzhiyun 	else if (status & DP83867_PHYSTS_100)
334*4882a593Smuzhiyun 		phydev->speed = SPEED_100;
335*4882a593Smuzhiyun 	else
336*4882a593Smuzhiyun 		phydev->speed = SPEED_10;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	return 0;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
dp83867_get_downshift(struct phy_device * phydev,u8 * data)341*4882a593Smuzhiyun static int dp83867_get_downshift(struct phy_device *phydev, u8 *data)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	int val, cnt, enable, count;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	val = phy_read(phydev, DP83867_CFG2);
346*4882a593Smuzhiyun 	if (val < 0)
347*4882a593Smuzhiyun 		return val;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	enable = FIELD_GET(DP83867_DOWNSHIFT_EN, val);
350*4882a593Smuzhiyun 	cnt = FIELD_GET(DP83867_DOWNSHIFT_ATTEMPT_MASK, val);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	switch (cnt) {
353*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_1_COUNT_VAL:
354*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_1_COUNT;
355*4882a593Smuzhiyun 		break;
356*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_2_COUNT_VAL:
357*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_2_COUNT;
358*4882a593Smuzhiyun 		break;
359*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_4_COUNT_VAL:
360*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_4_COUNT;
361*4882a593Smuzhiyun 		break;
362*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_8_COUNT_VAL:
363*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_8_COUNT;
364*4882a593Smuzhiyun 		break;
365*4882a593Smuzhiyun 	default:
366*4882a593Smuzhiyun 		return -EINVAL;
367*4882a593Smuzhiyun 	}
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	*data = enable ? count : DOWNSHIFT_DEV_DISABLE;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
dp83867_set_downshift(struct phy_device * phydev,u8 cnt)374*4882a593Smuzhiyun static int dp83867_set_downshift(struct phy_device *phydev, u8 cnt)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	int val, count;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (cnt > DP83867_DOWNSHIFT_8_COUNT)
379*4882a593Smuzhiyun 		return -E2BIG;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (!cnt)
382*4882a593Smuzhiyun 		return phy_clear_bits(phydev, DP83867_CFG2,
383*4882a593Smuzhiyun 				      DP83867_DOWNSHIFT_EN);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	switch (cnt) {
386*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_1_COUNT:
387*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_1_COUNT_VAL;
388*4882a593Smuzhiyun 		break;
389*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_2_COUNT:
390*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_2_COUNT_VAL;
391*4882a593Smuzhiyun 		break;
392*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_4_COUNT:
393*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_4_COUNT_VAL;
394*4882a593Smuzhiyun 		break;
395*4882a593Smuzhiyun 	case DP83867_DOWNSHIFT_8_COUNT:
396*4882a593Smuzhiyun 		count = DP83867_DOWNSHIFT_8_COUNT_VAL;
397*4882a593Smuzhiyun 		break;
398*4882a593Smuzhiyun 	default:
399*4882a593Smuzhiyun 		phydev_err(phydev,
400*4882a593Smuzhiyun 			   "Downshift count must be 1, 2, 4 or 8\n");
401*4882a593Smuzhiyun 		return -EINVAL;
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	val = DP83867_DOWNSHIFT_EN;
405*4882a593Smuzhiyun 	val |= FIELD_PREP(DP83867_DOWNSHIFT_ATTEMPT_MASK, count);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	return phy_modify(phydev, DP83867_CFG2,
408*4882a593Smuzhiyun 			  DP83867_DOWNSHIFT_EN | DP83867_DOWNSHIFT_ATTEMPT_MASK,
409*4882a593Smuzhiyun 			  val);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
dp83867_get_tunable(struct phy_device * phydev,struct ethtool_tunable * tuna,void * data)412*4882a593Smuzhiyun static int dp83867_get_tunable(struct phy_device *phydev,
413*4882a593Smuzhiyun 			       struct ethtool_tunable *tuna, void *data)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	switch (tuna->id) {
416*4882a593Smuzhiyun 	case ETHTOOL_PHY_DOWNSHIFT:
417*4882a593Smuzhiyun 		return dp83867_get_downshift(phydev, data);
418*4882a593Smuzhiyun 	default:
419*4882a593Smuzhiyun 		return -EOPNOTSUPP;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
dp83867_set_tunable(struct phy_device * phydev,struct ethtool_tunable * tuna,const void * data)423*4882a593Smuzhiyun static int dp83867_set_tunable(struct phy_device *phydev,
424*4882a593Smuzhiyun 			       struct ethtool_tunable *tuna, const void *data)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	switch (tuna->id) {
427*4882a593Smuzhiyun 	case ETHTOOL_PHY_DOWNSHIFT:
428*4882a593Smuzhiyun 		return dp83867_set_downshift(phydev, *(const u8 *)data);
429*4882a593Smuzhiyun 	default:
430*4882a593Smuzhiyun 		return -EOPNOTSUPP;
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
dp83867_config_port_mirroring(struct phy_device * phydev)434*4882a593Smuzhiyun static int dp83867_config_port_mirroring(struct phy_device *phydev)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	struct dp83867_private *dp83867 =
437*4882a593Smuzhiyun 		(struct dp83867_private *)phydev->priv;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (dp83867->port_mirroring == DP83867_PORT_MIRROING_EN)
440*4882a593Smuzhiyun 		phy_set_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
441*4882a593Smuzhiyun 				 DP83867_CFG4_PORT_MIRROR_EN);
442*4882a593Smuzhiyun 	else
443*4882a593Smuzhiyun 		phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
444*4882a593Smuzhiyun 				   DP83867_CFG4_PORT_MIRROR_EN);
445*4882a593Smuzhiyun 	return 0;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
dp83867_verify_rgmii_cfg(struct phy_device * phydev)448*4882a593Smuzhiyun static int dp83867_verify_rgmii_cfg(struct phy_device *phydev)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct dp83867_private *dp83867 = phydev->priv;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	/* Existing behavior was to use default pin strapping delay in rgmii
453*4882a593Smuzhiyun 	 * mode, but rgmii should have meant no delay.  Warn existing users.
454*4882a593Smuzhiyun 	 */
455*4882a593Smuzhiyun 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
456*4882a593Smuzhiyun 		const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR,
457*4882a593Smuzhiyun 					     DP83867_STRAP_STS2);
458*4882a593Smuzhiyun 		const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
459*4882a593Smuzhiyun 				   DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
460*4882a593Smuzhiyun 		const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
461*4882a593Smuzhiyun 				   DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 		if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
464*4882a593Smuzhiyun 		    rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
465*4882a593Smuzhiyun 			phydev_warn(phydev,
466*4882a593Smuzhiyun 				    "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
467*4882a593Smuzhiyun 				    "Should be 'rgmii-id' to use internal delays txskew:%x rxskew:%x\n",
468*4882a593Smuzhiyun 				    txskew, rxskew);
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/* RX delay *must* be specified if internal delay of RX is used. */
472*4882a593Smuzhiyun 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
473*4882a593Smuzhiyun 	     phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) &&
474*4882a593Smuzhiyun 	     dp83867->rx_id_delay == DP83867_RGMII_RX_CLK_DELAY_INV) {
475*4882a593Smuzhiyun 		phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
476*4882a593Smuzhiyun 		return -EINVAL;
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	/* TX delay *must* be specified if internal delay of TX is used. */
480*4882a593Smuzhiyun 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
481*4882a593Smuzhiyun 	     phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) &&
482*4882a593Smuzhiyun 	     dp83867->tx_id_delay == DP83867_RGMII_TX_CLK_DELAY_INV) {
483*4882a593Smuzhiyun 		phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
484*4882a593Smuzhiyun 		return -EINVAL;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_OF_MDIO)
dp83867_of_init(struct phy_device * phydev)491*4882a593Smuzhiyun static int dp83867_of_init(struct phy_device *phydev)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	struct dp83867_private *dp83867 = phydev->priv;
494*4882a593Smuzhiyun 	struct device *dev = &phydev->mdio.dev;
495*4882a593Smuzhiyun 	struct device_node *of_node = dev->of_node;
496*4882a593Smuzhiyun 	int ret;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	if (!of_node)
499*4882a593Smuzhiyun 		return -ENODEV;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	/* Optional configuration */
502*4882a593Smuzhiyun 	ret = of_property_read_u32(of_node, "ti,clk-output-sel",
503*4882a593Smuzhiyun 				   &dp83867->clk_output_sel);
504*4882a593Smuzhiyun 	/* If not set, keep default */
505*4882a593Smuzhiyun 	if (!ret) {
506*4882a593Smuzhiyun 		dp83867->set_clk_output = true;
507*4882a593Smuzhiyun 		/* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or
508*4882a593Smuzhiyun 		 * DP83867_CLK_O_SEL_OFF.
509*4882a593Smuzhiyun 		 */
510*4882a593Smuzhiyun 		if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK &&
511*4882a593Smuzhiyun 		    dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) {
512*4882a593Smuzhiyun 			phydev_err(phydev, "ti,clk-output-sel value %u out of range\n",
513*4882a593Smuzhiyun 				   dp83867->clk_output_sel);
514*4882a593Smuzhiyun 			return -EINVAL;
515*4882a593Smuzhiyun 		}
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	if (of_property_read_bool(of_node, "ti,max-output-impedance"))
519*4882a593Smuzhiyun 		dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
520*4882a593Smuzhiyun 	else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
521*4882a593Smuzhiyun 		dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
522*4882a593Smuzhiyun 	else
523*4882a593Smuzhiyun 		dp83867->io_impedance = -1; /* leave at default */
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node,
526*4882a593Smuzhiyun 							    "ti,dp83867-rxctrl-strap-quirk");
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node,
529*4882a593Smuzhiyun 							  "ti,sgmii-ref-clock-output-enable");
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	dp83867->rx_id_delay = DP83867_RGMII_RX_CLK_DELAY_INV;
532*4882a593Smuzhiyun 	ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
533*4882a593Smuzhiyun 				   &dp83867->rx_id_delay);
534*4882a593Smuzhiyun 	if (!ret && dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
535*4882a593Smuzhiyun 		phydev_err(phydev,
536*4882a593Smuzhiyun 			   "ti,rx-internal-delay value of %u out of range\n",
537*4882a593Smuzhiyun 			   dp83867->rx_id_delay);
538*4882a593Smuzhiyun 		return -EINVAL;
539*4882a593Smuzhiyun 	}
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	dp83867->tx_id_delay = DP83867_RGMII_TX_CLK_DELAY_INV;
542*4882a593Smuzhiyun 	ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
543*4882a593Smuzhiyun 				   &dp83867->tx_id_delay);
544*4882a593Smuzhiyun 	if (!ret && dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
545*4882a593Smuzhiyun 		phydev_err(phydev,
546*4882a593Smuzhiyun 			   "ti,tx-internal-delay value of %u out of range\n",
547*4882a593Smuzhiyun 			   dp83867->tx_id_delay);
548*4882a593Smuzhiyun 		return -EINVAL;
549*4882a593Smuzhiyun 	}
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
552*4882a593Smuzhiyun 		dp83867->port_mirroring = DP83867_PORT_MIRROING_EN;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (of_property_read_bool(of_node, "enet-phy-lane-no-swap"))
555*4882a593Smuzhiyun 		dp83867->port_mirroring = DP83867_PORT_MIRROING_DIS;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	ret = of_property_read_u32(of_node, "ti,fifo-depth",
558*4882a593Smuzhiyun 				   &dp83867->tx_fifo_depth);
559*4882a593Smuzhiyun 	if (ret) {
560*4882a593Smuzhiyun 		ret = of_property_read_u32(of_node, "tx-fifo-depth",
561*4882a593Smuzhiyun 					   &dp83867->tx_fifo_depth);
562*4882a593Smuzhiyun 		if (ret)
563*4882a593Smuzhiyun 			dp83867->tx_fifo_depth =
564*4882a593Smuzhiyun 					DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	if (dp83867->tx_fifo_depth > DP83867_PHYCR_FIFO_DEPTH_MAX) {
568*4882a593Smuzhiyun 		phydev_err(phydev, "tx-fifo-depth value %u out of range\n",
569*4882a593Smuzhiyun 			   dp83867->tx_fifo_depth);
570*4882a593Smuzhiyun 		return -EINVAL;
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	ret = of_property_read_u32(of_node, "rx-fifo-depth",
574*4882a593Smuzhiyun 				   &dp83867->rx_fifo_depth);
575*4882a593Smuzhiyun 	if (ret)
576*4882a593Smuzhiyun 		dp83867->rx_fifo_depth = DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	if (dp83867->rx_fifo_depth > DP83867_PHYCR_FIFO_DEPTH_MAX) {
579*4882a593Smuzhiyun 		phydev_err(phydev, "rx-fifo-depth value %u out of range\n",
580*4882a593Smuzhiyun 			   dp83867->rx_fifo_depth);
581*4882a593Smuzhiyun 		return -EINVAL;
582*4882a593Smuzhiyun 	}
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	return 0;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun #else
dp83867_of_init(struct phy_device * phydev)587*4882a593Smuzhiyun static int dp83867_of_init(struct phy_device *phydev)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	return 0;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun #endif /* CONFIG_OF_MDIO */
592*4882a593Smuzhiyun 
dp83867_probe(struct phy_device * phydev)593*4882a593Smuzhiyun static int dp83867_probe(struct phy_device *phydev)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun 	struct dp83867_private *dp83867;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867),
598*4882a593Smuzhiyun 			       GFP_KERNEL);
599*4882a593Smuzhiyun 	if (!dp83867)
600*4882a593Smuzhiyun 		return -ENOMEM;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	phydev->priv = dp83867;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	return dp83867_of_init(phydev);
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
dp83867_config_init(struct phy_device * phydev)607*4882a593Smuzhiyun static int dp83867_config_init(struct phy_device *phydev)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	struct dp83867_private *dp83867 = phydev->priv;
610*4882a593Smuzhiyun 	int ret, val, bs;
611*4882a593Smuzhiyun 	u16 delay;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	/* Force speed optimization for the PHY even if it strapped */
614*4882a593Smuzhiyun 	ret = phy_modify(phydev, DP83867_CFG2, DP83867_DOWNSHIFT_EN,
615*4882a593Smuzhiyun 			 DP83867_DOWNSHIFT_EN);
616*4882a593Smuzhiyun 	if (ret)
617*4882a593Smuzhiyun 		return ret;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	ret = dp83867_verify_rgmii_cfg(phydev);
620*4882a593Smuzhiyun 	if (ret)
621*4882a593Smuzhiyun 		return ret;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	/* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
624*4882a593Smuzhiyun 	if (dp83867->rxctrl_strap_quirk)
625*4882a593Smuzhiyun 		phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
626*4882a593Smuzhiyun 				   BIT(7));
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
629*4882a593Smuzhiyun 	if (bs & DP83867_STRAP_STS2_STRAP_FLD) {
630*4882a593Smuzhiyun 		/* When using strap to enable FLD, the ENERGY_LOST_FLD_THR will
631*4882a593Smuzhiyun 		 * be set to 0x2. This may causes the PHY link to be unstable -
632*4882a593Smuzhiyun 		 * the default value 0x1 need to be restored.
633*4882a593Smuzhiyun 		 */
634*4882a593Smuzhiyun 		ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
635*4882a593Smuzhiyun 				     DP83867_FLD_THR_CFG,
636*4882a593Smuzhiyun 				     DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK,
637*4882a593Smuzhiyun 				     0x1);
638*4882a593Smuzhiyun 		if (ret)
639*4882a593Smuzhiyun 			return ret;
640*4882a593Smuzhiyun 	}
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	if (phy_interface_is_rgmii(phydev) ||
643*4882a593Smuzhiyun 	    phydev->interface == PHY_INTERFACE_MODE_SGMII) {
644*4882a593Smuzhiyun 		val = phy_read(phydev, MII_DP83867_PHYCTRL);
645*4882a593Smuzhiyun 		if (val < 0)
646*4882a593Smuzhiyun 			return val;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 		val &= ~DP83867_PHYCR_TX_FIFO_DEPTH_MASK;
649*4882a593Smuzhiyun 		val |= (dp83867->tx_fifo_depth <<
650*4882a593Smuzhiyun 			DP83867_PHYCR_TX_FIFO_DEPTH_SHIFT);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 		if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
653*4882a593Smuzhiyun 			val &= ~DP83867_PHYCR_RX_FIFO_DEPTH_MASK;
654*4882a593Smuzhiyun 			val |= (dp83867->rx_fifo_depth <<
655*4882a593Smuzhiyun 				DP83867_PHYCR_RX_FIFO_DEPTH_SHIFT);
656*4882a593Smuzhiyun 		}
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 		ret = phy_write(phydev, MII_DP83867_PHYCTRL, val);
659*4882a593Smuzhiyun 		if (ret)
660*4882a593Smuzhiyun 			return ret;
661*4882a593Smuzhiyun 	}
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	if (phy_interface_is_rgmii(phydev)) {
664*4882a593Smuzhiyun 		val = phy_read(phydev, MII_DP83867_PHYCTRL);
665*4882a593Smuzhiyun 		if (val < 0)
666*4882a593Smuzhiyun 			return val;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 		/* The code below checks if "port mirroring" N/A MODE4 has been
669*4882a593Smuzhiyun 		 * enabled during power on bootstrap.
670*4882a593Smuzhiyun 		 *
671*4882a593Smuzhiyun 		 * Such N/A mode enabled by mistake can put PHY IC in some
672*4882a593Smuzhiyun 		 * internal testing mode and disable RGMII transmission.
673*4882a593Smuzhiyun 		 *
674*4882a593Smuzhiyun 		 * In this particular case one needs to check STRAP_STS1
675*4882a593Smuzhiyun 		 * register's bit 11 (marked as RESERVED).
676*4882a593Smuzhiyun 		 */
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 		bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS1);
679*4882a593Smuzhiyun 		if (bs & DP83867_STRAP_STS1_RESERVED)
680*4882a593Smuzhiyun 			val &= ~DP83867_PHYCR_RESERVED_MASK;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 		ret = phy_write(phydev, MII_DP83867_PHYCTRL, val);
683*4882a593Smuzhiyun 		if (ret)
684*4882a593Smuzhiyun 			return ret;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 		/* If rgmii mode with no internal delay is selected, we do NOT use
687*4882a593Smuzhiyun 		 * aligned mode as one might expect.  Instead we use the PHY's default
688*4882a593Smuzhiyun 		 * based on pin strapping.  And the "mode 0" default is to *use*
689*4882a593Smuzhiyun 		 * internal delay with a value of 7 (2.00 ns).
690*4882a593Smuzhiyun 		 *
691*4882a593Smuzhiyun 		 * Set up RGMII delays
692*4882a593Smuzhiyun 		 */
693*4882a593Smuzhiyun 		val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 		val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
696*4882a593Smuzhiyun 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
697*4882a593Smuzhiyun 			val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
700*4882a593Smuzhiyun 			val |= DP83867_RGMII_TX_CLK_DELAY_EN;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
703*4882a593Smuzhiyun 			val |= DP83867_RGMII_RX_CLK_DELAY_EN;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val);
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 		delay = 0;
708*4882a593Smuzhiyun 		if (dp83867->rx_id_delay != DP83867_RGMII_RX_CLK_DELAY_INV)
709*4882a593Smuzhiyun 			delay |= dp83867->rx_id_delay;
710*4882a593Smuzhiyun 		if (dp83867->tx_id_delay != DP83867_RGMII_TX_CLK_DELAY_INV)
711*4882a593Smuzhiyun 			delay |= dp83867->tx_id_delay <<
712*4882a593Smuzhiyun 				 DP83867_RGMII_TX_CLK_DELAY_SHIFT;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL,
715*4882a593Smuzhiyun 			      delay);
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/* If specified, set io impedance */
719*4882a593Smuzhiyun 	if (dp83867->io_impedance >= 0)
720*4882a593Smuzhiyun 		phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
721*4882a593Smuzhiyun 			       DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK,
722*4882a593Smuzhiyun 			       dp83867->io_impedance);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
725*4882a593Smuzhiyun 		/* For support SPEED_10 in SGMII mode
726*4882a593Smuzhiyun 		 * DP83867_10M_SGMII_RATE_ADAPT bit
727*4882a593Smuzhiyun 		 * has to be cleared by software. That
728*4882a593Smuzhiyun 		 * does not affect SPEED_100 and
729*4882a593Smuzhiyun 		 * SPEED_1000.
730*4882a593Smuzhiyun 		 */
731*4882a593Smuzhiyun 		ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
732*4882a593Smuzhiyun 				     DP83867_10M_SGMII_CFG,
733*4882a593Smuzhiyun 				     DP83867_10M_SGMII_RATE_ADAPT_MASK,
734*4882a593Smuzhiyun 				     0);
735*4882a593Smuzhiyun 		if (ret)
736*4882a593Smuzhiyun 			return ret;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 		/* After reset SGMII Autoneg timer is set to 2us (bits 6 and 5
739*4882a593Smuzhiyun 		 * are 01). That is not enough to finalize autoneg on some
740*4882a593Smuzhiyun 		 * devices. Increase this timer duration to maximum 16ms.
741*4882a593Smuzhiyun 		 */
742*4882a593Smuzhiyun 		ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
743*4882a593Smuzhiyun 				     DP83867_CFG4,
744*4882a593Smuzhiyun 				     DP83867_CFG4_SGMII_ANEG_MASK,
745*4882a593Smuzhiyun 				     DP83867_CFG4_SGMII_ANEG_TIMER_16MS);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		if (ret)
748*4882a593Smuzhiyun 			return ret;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 		val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL);
751*4882a593Smuzhiyun 		/* SGMII type is set to 4-wire mode by default.
752*4882a593Smuzhiyun 		 * If we place appropriate property in dts (see above)
753*4882a593Smuzhiyun 		 * switch on 6-wire mode.
754*4882a593Smuzhiyun 		 */
755*4882a593Smuzhiyun 		if (dp83867->sgmii_ref_clk_en)
756*4882a593Smuzhiyun 			val |= DP83867_SGMII_TYPE;
757*4882a593Smuzhiyun 		else
758*4882a593Smuzhiyun 			val &= ~DP83867_SGMII_TYPE;
759*4882a593Smuzhiyun 		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL, val);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 		/* This is a SW workaround for link instability if RX_CTRL is
762*4882a593Smuzhiyun 		 * not strapped to mode 3 or 4 in HW. This is required for SGMII
763*4882a593Smuzhiyun 		 * in addition to clearing bit 7, handled above.
764*4882a593Smuzhiyun 		 */
765*4882a593Smuzhiyun 		if (dp83867->rxctrl_strap_quirk)
766*4882a593Smuzhiyun 			phy_set_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
767*4882a593Smuzhiyun 					 BIT(8));
768*4882a593Smuzhiyun 	}
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	val = phy_read(phydev, DP83867_CFG3);
771*4882a593Smuzhiyun 	/* Enable Interrupt output INT_OE in CFG3 register */
772*4882a593Smuzhiyun 	if (phy_interrupt_is_valid(phydev))
773*4882a593Smuzhiyun 		val |= DP83867_CFG3_INT_OE;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	val |= DP83867_CFG3_ROBUST_AUTO_MDIX;
776*4882a593Smuzhiyun 	phy_write(phydev, DP83867_CFG3, val);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
779*4882a593Smuzhiyun 		dp83867_config_port_mirroring(phydev);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	/* Clock output selection if muxing property is set */
782*4882a593Smuzhiyun 	if (dp83867->set_clk_output) {
783*4882a593Smuzhiyun 		u16 mask = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 		if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) {
786*4882a593Smuzhiyun 			val = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
787*4882a593Smuzhiyun 		} else {
788*4882a593Smuzhiyun 			mask |= DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
789*4882a593Smuzhiyun 			val = dp83867->clk_output_sel <<
790*4882a593Smuzhiyun 			      DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT;
791*4882a593Smuzhiyun 		}
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 		phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
794*4882a593Smuzhiyun 			       mask, val);
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	return 0;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun 
dp83867_phy_reset(struct phy_device * phydev)800*4882a593Smuzhiyun static int dp83867_phy_reset(struct phy_device *phydev)
801*4882a593Smuzhiyun {
802*4882a593Smuzhiyun 	int err;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESTART);
805*4882a593Smuzhiyun 	if (err < 0)
806*4882a593Smuzhiyun 		return err;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	usleep_range(10, 20);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	return phy_modify(phydev, MII_DP83867_PHYCTRL,
811*4882a593Smuzhiyun 			 DP83867_PHYCR_FORCE_LINK_GOOD, 0);
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun 
dp83867_link_change_notify(struct phy_device * phydev)814*4882a593Smuzhiyun static void dp83867_link_change_notify(struct phy_device *phydev)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun 	/* There is a limitation in DP83867 PHY device where SGMII AN is
817*4882a593Smuzhiyun 	 * only triggered once after the device is booted up. Even after the
818*4882a593Smuzhiyun 	 * PHY TPI is down and up again, SGMII AN is not triggered and
819*4882a593Smuzhiyun 	 * hence no new in-band message from PHY to MAC side SGMII.
820*4882a593Smuzhiyun 	 * This could cause an issue during power up, when PHY is up prior
821*4882a593Smuzhiyun 	 * to MAC. At this condition, once MAC side SGMII is up, MAC side
822*4882a593Smuzhiyun 	 * SGMII wouldn`t receive new in-band message from TI PHY with
823*4882a593Smuzhiyun 	 * correct link status, speed and duplex info.
824*4882a593Smuzhiyun 	 * Thus, implemented a SW solution here to retrigger SGMII Auto-Neg
825*4882a593Smuzhiyun 	 * whenever there is a link change.
826*4882a593Smuzhiyun 	 */
827*4882a593Smuzhiyun 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
828*4882a593Smuzhiyun 		int val = 0;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 		val = phy_clear_bits(phydev, DP83867_CFG2,
831*4882a593Smuzhiyun 				     DP83867_SGMII_AUTONEG_EN);
832*4882a593Smuzhiyun 		if (val < 0)
833*4882a593Smuzhiyun 			return;
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 		phy_set_bits(phydev, DP83867_CFG2,
836*4882a593Smuzhiyun 			     DP83867_SGMII_AUTONEG_EN);
837*4882a593Smuzhiyun 	}
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun static struct phy_driver dp83867_driver[] = {
841*4882a593Smuzhiyun 	{
842*4882a593Smuzhiyun 		.phy_id		= DP83867_PHY_ID,
843*4882a593Smuzhiyun 		.phy_id_mask	= 0xfffffff0,
844*4882a593Smuzhiyun 		.name		= "TI DP83867",
845*4882a593Smuzhiyun 		/* PHY_GBIT_FEATURES */
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 		.probe          = dp83867_probe,
848*4882a593Smuzhiyun 		.config_init	= dp83867_config_init,
849*4882a593Smuzhiyun 		.soft_reset	= dp83867_phy_reset,
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 		.read_status	= dp83867_read_status,
852*4882a593Smuzhiyun 		.get_tunable	= dp83867_get_tunable,
853*4882a593Smuzhiyun 		.set_tunable	= dp83867_set_tunable,
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 		.get_wol	= dp83867_get_wol,
856*4882a593Smuzhiyun 		.set_wol	= dp83867_set_wol,
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 		/* IRQ related */
859*4882a593Smuzhiyun 		.ack_interrupt	= dp83867_ack_interrupt,
860*4882a593Smuzhiyun 		.config_intr	= dp83867_config_intr,
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
863*4882a593Smuzhiyun 		.resume		= genphy_resume,
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 		.link_change_notify = dp83867_link_change_notify,
866*4882a593Smuzhiyun 	},
867*4882a593Smuzhiyun };
868*4882a593Smuzhiyun module_phy_driver(dp83867_driver);
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun static struct mdio_device_id __maybe_unused dp83867_tbl[] = {
871*4882a593Smuzhiyun 	{ DP83867_PHY_ID, 0xfffffff0 },
872*4882a593Smuzhiyun 	{ }
873*4882a593Smuzhiyun };
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mdio, dp83867_tbl);
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun MODULE_DESCRIPTION("Texas Instruments DP83867 PHY driver");
878*4882a593Smuzhiyun MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
879*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
880