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