xref: /rk3399_rockchip-uboot/drivers/net/phy/phy.c (revision 5f184715ecd31bfcb8d09ba2d9f14adfa172a141)
1*5f184715SAndy Fleming /*
2*5f184715SAndy Fleming  * Generic PHY Management code
3*5f184715SAndy Fleming  *
4*5f184715SAndy Fleming  * This program is free software; you can redistribute it and/or
5*5f184715SAndy Fleming  * modify it under the terms of the GNU General Public License as
6*5f184715SAndy Fleming  * published by the Free Software Foundation; either version 2 of
7*5f184715SAndy Fleming  * the License, or (at your option) any later version.
8*5f184715SAndy Fleming  *
9*5f184715SAndy Fleming  * This program is distributed in the hope that it will be useful,
10*5f184715SAndy Fleming  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*5f184715SAndy Fleming  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*5f184715SAndy Fleming  * GNU General Public License for more details.
13*5f184715SAndy Fleming  *
14*5f184715SAndy Fleming  * You should have received a copy of the GNU General Public License
15*5f184715SAndy Fleming  * along with this program; if not, write to the Free Software
16*5f184715SAndy Fleming  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17*5f184715SAndy Fleming  * MA 02111-1307 USA
18*5f184715SAndy Fleming  *
19*5f184715SAndy Fleming  *
20*5f184715SAndy Fleming  * Copyright 2011 Freescale Semiconductor, Inc.
21*5f184715SAndy Fleming  * author Andy Fleming
22*5f184715SAndy Fleming  *
23*5f184715SAndy Fleming  * Based loosely off of Linux's PHY Lib
24*5f184715SAndy Fleming  */
25*5f184715SAndy Fleming 
26*5f184715SAndy Fleming #include <config.h>
27*5f184715SAndy Fleming #include <common.h>
28*5f184715SAndy Fleming #include <malloc.h>
29*5f184715SAndy Fleming #include <net.h>
30*5f184715SAndy Fleming #include <command.h>
31*5f184715SAndy Fleming #include <miiphy.h>
32*5f184715SAndy Fleming #include <phy.h>
33*5f184715SAndy Fleming #include <errno.h>
34*5f184715SAndy Fleming 
35*5f184715SAndy Fleming /* Generic PHY support and helper functions */
36*5f184715SAndy Fleming 
37*5f184715SAndy Fleming /**
38*5f184715SAndy Fleming  * genphy_config_advert - sanitize and advertise auto-negotation parameters
39*5f184715SAndy Fleming  * @phydev: target phy_device struct
40*5f184715SAndy Fleming  *
41*5f184715SAndy Fleming  * Description: Writes MII_ADVERTISE with the appropriate values,
42*5f184715SAndy Fleming  *   after sanitizing the values to make sure we only advertise
43*5f184715SAndy Fleming  *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
44*5f184715SAndy Fleming  *   hasn't changed, and > 0 if it has changed.
45*5f184715SAndy Fleming  */
46*5f184715SAndy Fleming int genphy_config_advert(struct phy_device *phydev)
47*5f184715SAndy Fleming {
48*5f184715SAndy Fleming 	u32 advertise;
49*5f184715SAndy Fleming 	int oldadv, adv;
50*5f184715SAndy Fleming 	int err, changed = 0;
51*5f184715SAndy Fleming 
52*5f184715SAndy Fleming 	/* Only allow advertising what
53*5f184715SAndy Fleming 	 * this PHY supports */
54*5f184715SAndy Fleming 	phydev->advertising &= phydev->supported;
55*5f184715SAndy Fleming 	advertise = phydev->advertising;
56*5f184715SAndy Fleming 
57*5f184715SAndy Fleming 	/* Setup standard advertisement */
58*5f184715SAndy Fleming 	oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
59*5f184715SAndy Fleming 
60*5f184715SAndy Fleming 	if (adv < 0)
61*5f184715SAndy Fleming 		return adv;
62*5f184715SAndy Fleming 
63*5f184715SAndy Fleming 	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
64*5f184715SAndy Fleming 		 ADVERTISE_PAUSE_ASYM);
65*5f184715SAndy Fleming 	if (advertise & ADVERTISED_10baseT_Half)
66*5f184715SAndy Fleming 		adv |= ADVERTISE_10HALF;
67*5f184715SAndy Fleming 	if (advertise & ADVERTISED_10baseT_Full)
68*5f184715SAndy Fleming 		adv |= ADVERTISE_10FULL;
69*5f184715SAndy Fleming 	if (advertise & ADVERTISED_100baseT_Half)
70*5f184715SAndy Fleming 		adv |= ADVERTISE_100HALF;
71*5f184715SAndy Fleming 	if (advertise & ADVERTISED_100baseT_Full)
72*5f184715SAndy Fleming 		adv |= ADVERTISE_100FULL;
73*5f184715SAndy Fleming 	if (advertise & ADVERTISED_Pause)
74*5f184715SAndy Fleming 		adv |= ADVERTISE_PAUSE_CAP;
75*5f184715SAndy Fleming 	if (advertise & ADVERTISED_Asym_Pause)
76*5f184715SAndy Fleming 		adv |= ADVERTISE_PAUSE_ASYM;
77*5f184715SAndy Fleming 
78*5f184715SAndy Fleming 	if (adv != oldadv) {
79*5f184715SAndy Fleming 		err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
80*5f184715SAndy Fleming 
81*5f184715SAndy Fleming 		if (err < 0)
82*5f184715SAndy Fleming 			return err;
83*5f184715SAndy Fleming 		changed = 1;
84*5f184715SAndy Fleming 	}
85*5f184715SAndy Fleming 
86*5f184715SAndy Fleming 	/* Configure gigabit if it's supported */
87*5f184715SAndy Fleming 	if (phydev->supported & (SUPPORTED_1000baseT_Half |
88*5f184715SAndy Fleming 				SUPPORTED_1000baseT_Full)) {
89*5f184715SAndy Fleming 		oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
90*5f184715SAndy Fleming 
91*5f184715SAndy Fleming 		if (adv < 0)
92*5f184715SAndy Fleming 			return adv;
93*5f184715SAndy Fleming 
94*5f184715SAndy Fleming 		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
95*5f184715SAndy Fleming 		if (advertise & SUPPORTED_1000baseT_Half)
96*5f184715SAndy Fleming 			adv |= ADVERTISE_1000HALF;
97*5f184715SAndy Fleming 		if (advertise & SUPPORTED_1000baseT_Full)
98*5f184715SAndy Fleming 			adv |= ADVERTISE_1000FULL;
99*5f184715SAndy Fleming 
100*5f184715SAndy Fleming 		if (adv != oldadv) {
101*5f184715SAndy Fleming 			err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
102*5f184715SAndy Fleming 					adv);
103*5f184715SAndy Fleming 
104*5f184715SAndy Fleming 			if (err < 0)
105*5f184715SAndy Fleming 				return err;
106*5f184715SAndy Fleming 			changed = 1;
107*5f184715SAndy Fleming 		}
108*5f184715SAndy Fleming 	}
109*5f184715SAndy Fleming 
110*5f184715SAndy Fleming 	return changed;
111*5f184715SAndy Fleming }
112*5f184715SAndy Fleming 
113*5f184715SAndy Fleming 
114*5f184715SAndy Fleming /**
115*5f184715SAndy Fleming  * genphy_setup_forced - configures/forces speed/duplex from @phydev
116*5f184715SAndy Fleming  * @phydev: target phy_device struct
117*5f184715SAndy Fleming  *
118*5f184715SAndy Fleming  * Description: Configures MII_BMCR to force speed/duplex
119*5f184715SAndy Fleming  *   to the values in phydev. Assumes that the values are valid.
120*5f184715SAndy Fleming  */
121*5f184715SAndy Fleming int genphy_setup_forced(struct phy_device *phydev)
122*5f184715SAndy Fleming {
123*5f184715SAndy Fleming 	int err;
124*5f184715SAndy Fleming 	int ctl = 0;
125*5f184715SAndy Fleming 
126*5f184715SAndy Fleming 	phydev->pause = phydev->asym_pause = 0;
127*5f184715SAndy Fleming 
128*5f184715SAndy Fleming 	if (SPEED_1000 == phydev->speed)
129*5f184715SAndy Fleming 		ctl |= BMCR_SPEED1000;
130*5f184715SAndy Fleming 	else if (SPEED_100 == phydev->speed)
131*5f184715SAndy Fleming 		ctl |= BMCR_SPEED100;
132*5f184715SAndy Fleming 
133*5f184715SAndy Fleming 	if (DUPLEX_FULL == phydev->duplex)
134*5f184715SAndy Fleming 		ctl |= BMCR_FULLDPLX;
135*5f184715SAndy Fleming 
136*5f184715SAndy Fleming 	err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
137*5f184715SAndy Fleming 
138*5f184715SAndy Fleming 	return err;
139*5f184715SAndy Fleming }
140*5f184715SAndy Fleming 
141*5f184715SAndy Fleming 
142*5f184715SAndy Fleming /**
143*5f184715SAndy Fleming  * genphy_restart_aneg - Enable and Restart Autonegotiation
144*5f184715SAndy Fleming  * @phydev: target phy_device struct
145*5f184715SAndy Fleming  */
146*5f184715SAndy Fleming int genphy_restart_aneg(struct phy_device *phydev)
147*5f184715SAndy Fleming {
148*5f184715SAndy Fleming 	int ctl;
149*5f184715SAndy Fleming 
150*5f184715SAndy Fleming 	ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
151*5f184715SAndy Fleming 
152*5f184715SAndy Fleming 	if (ctl < 0)
153*5f184715SAndy Fleming 		return ctl;
154*5f184715SAndy Fleming 
155*5f184715SAndy Fleming 	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
156*5f184715SAndy Fleming 
157*5f184715SAndy Fleming 	/* Don't isolate the PHY if we're negotiating */
158*5f184715SAndy Fleming 	ctl &= ~(BMCR_ISOLATE);
159*5f184715SAndy Fleming 
160*5f184715SAndy Fleming 	ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
161*5f184715SAndy Fleming 
162*5f184715SAndy Fleming 	return ctl;
163*5f184715SAndy Fleming }
164*5f184715SAndy Fleming 
165*5f184715SAndy Fleming 
166*5f184715SAndy Fleming /**
167*5f184715SAndy Fleming  * genphy_config_aneg - restart auto-negotiation or write BMCR
168*5f184715SAndy Fleming  * @phydev: target phy_device struct
169*5f184715SAndy Fleming  *
170*5f184715SAndy Fleming  * Description: If auto-negotiation is enabled, we configure the
171*5f184715SAndy Fleming  *   advertising, and then restart auto-negotiation.  If it is not
172*5f184715SAndy Fleming  *   enabled, then we write the BMCR.
173*5f184715SAndy Fleming  */
174*5f184715SAndy Fleming int genphy_config_aneg(struct phy_device *phydev)
175*5f184715SAndy Fleming {
176*5f184715SAndy Fleming 	int result;
177*5f184715SAndy Fleming 
178*5f184715SAndy Fleming 	if (AUTONEG_ENABLE != phydev->autoneg)
179*5f184715SAndy Fleming 		return genphy_setup_forced(phydev);
180*5f184715SAndy Fleming 
181*5f184715SAndy Fleming 	result = genphy_config_advert(phydev);
182*5f184715SAndy Fleming 
183*5f184715SAndy Fleming 	if (result < 0) /* error */
184*5f184715SAndy Fleming 		return result;
185*5f184715SAndy Fleming 
186*5f184715SAndy Fleming 	if (result == 0) {
187*5f184715SAndy Fleming 		/* Advertisment hasn't changed, but maybe aneg was never on to
188*5f184715SAndy Fleming 		 * begin with?  Or maybe phy was isolated? */
189*5f184715SAndy Fleming 		int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
190*5f184715SAndy Fleming 
191*5f184715SAndy Fleming 		if (ctl < 0)
192*5f184715SAndy Fleming 			return ctl;
193*5f184715SAndy Fleming 
194*5f184715SAndy Fleming 		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
195*5f184715SAndy Fleming 			result = 1; /* do restart aneg */
196*5f184715SAndy Fleming 	}
197*5f184715SAndy Fleming 
198*5f184715SAndy Fleming 	/* Only restart aneg if we are advertising something different
199*5f184715SAndy Fleming 	 * than we were before.	 */
200*5f184715SAndy Fleming 	if (result > 0)
201*5f184715SAndy Fleming 		result = genphy_restart_aneg(phydev);
202*5f184715SAndy Fleming 
203*5f184715SAndy Fleming 	return result;
204*5f184715SAndy Fleming }
205*5f184715SAndy Fleming 
206*5f184715SAndy Fleming /**
207*5f184715SAndy Fleming  * genphy_update_link - update link status in @phydev
208*5f184715SAndy Fleming  * @phydev: target phy_device struct
209*5f184715SAndy Fleming  *
210*5f184715SAndy Fleming  * Description: Update the value in phydev->link to reflect the
211*5f184715SAndy Fleming  *   current link value.  In order to do this, we need to read
212*5f184715SAndy Fleming  *   the status register twice, keeping the second value.
213*5f184715SAndy Fleming  */
214*5f184715SAndy Fleming int genphy_update_link(struct phy_device *phydev)
215*5f184715SAndy Fleming {
216*5f184715SAndy Fleming 	unsigned int mii_reg;
217*5f184715SAndy Fleming 
218*5f184715SAndy Fleming 	/*
219*5f184715SAndy Fleming 	 * Wait if the link is up, and autonegotiation is in progress
220*5f184715SAndy Fleming 	 * (ie - we're capable and it's not done)
221*5f184715SAndy Fleming 	 */
222*5f184715SAndy Fleming 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
223*5f184715SAndy Fleming 
224*5f184715SAndy Fleming 	/*
225*5f184715SAndy Fleming 	 * If we already saw the link up, and it hasn't gone down, then
226*5f184715SAndy Fleming 	 * we don't need to wait for autoneg again
227*5f184715SAndy Fleming 	 */
228*5f184715SAndy Fleming 	if (phydev->link && mii_reg & BMSR_LSTATUS)
229*5f184715SAndy Fleming 		return 0;
230*5f184715SAndy Fleming 
231*5f184715SAndy Fleming 	if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
232*5f184715SAndy Fleming 		int i = 0;
233*5f184715SAndy Fleming 
234*5f184715SAndy Fleming 		printf("%s Waiting for PHY auto negotiation to complete",
235*5f184715SAndy Fleming 			phydev->dev->name);
236*5f184715SAndy Fleming 		while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
237*5f184715SAndy Fleming 			/*
238*5f184715SAndy Fleming 			 * Timeout reached ?
239*5f184715SAndy Fleming 			 */
240*5f184715SAndy Fleming 			if (i > PHY_ANEG_TIMEOUT) {
241*5f184715SAndy Fleming 				printf(" TIMEOUT !\n");
242*5f184715SAndy Fleming 				phydev->link = 0;
243*5f184715SAndy Fleming 				return 0;
244*5f184715SAndy Fleming 			}
245*5f184715SAndy Fleming 
246*5f184715SAndy Fleming 			if (ctrlc()) {
247*5f184715SAndy Fleming 				puts("user interrupt!\n");
248*5f184715SAndy Fleming 				phydev->link = 0;
249*5f184715SAndy Fleming 				return -EINTR;
250*5f184715SAndy Fleming 			}
251*5f184715SAndy Fleming 
252*5f184715SAndy Fleming 			if ((i++ % 500) == 0)
253*5f184715SAndy Fleming 				printf(".");
254*5f184715SAndy Fleming 
255*5f184715SAndy Fleming 			udelay(1000);	/* 1 ms */
256*5f184715SAndy Fleming 			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
257*5f184715SAndy Fleming 		}
258*5f184715SAndy Fleming 		printf(" done\n");
259*5f184715SAndy Fleming 		phydev->link = 1;
260*5f184715SAndy Fleming 	} else {
261*5f184715SAndy Fleming 		/* Read the link a second time to clear the latched state */
262*5f184715SAndy Fleming 		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
263*5f184715SAndy Fleming 
264*5f184715SAndy Fleming 		if (mii_reg & BMSR_LSTATUS)
265*5f184715SAndy Fleming 			phydev->link = 1;
266*5f184715SAndy Fleming 		else
267*5f184715SAndy Fleming 			phydev->link = 0;
268*5f184715SAndy Fleming 	}
269*5f184715SAndy Fleming 
270*5f184715SAndy Fleming 	return 0;
271*5f184715SAndy Fleming }
272*5f184715SAndy Fleming 
273*5f184715SAndy Fleming /*
274*5f184715SAndy Fleming  * Generic function which updates the speed and duplex.  If
275*5f184715SAndy Fleming  * autonegotiation is enabled, it uses the AND of the link
276*5f184715SAndy Fleming  * partner's advertised capabilities and our advertised
277*5f184715SAndy Fleming  * capabilities.  If autonegotiation is disabled, we use the
278*5f184715SAndy Fleming  * appropriate bits in the control register.
279*5f184715SAndy Fleming  *
280*5f184715SAndy Fleming  * Stolen from Linux's mii.c and phy_device.c
281*5f184715SAndy Fleming  */
282*5f184715SAndy Fleming static int genphy_parse_link(struct phy_device *phydev)
283*5f184715SAndy Fleming {
284*5f184715SAndy Fleming 	int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
285*5f184715SAndy Fleming 
286*5f184715SAndy Fleming 	/* We're using autonegotiation */
287*5f184715SAndy Fleming 	if (mii_reg & BMSR_ANEGCAPABLE) {
288*5f184715SAndy Fleming 		u32 lpa = 0;
289*5f184715SAndy Fleming 		u32 gblpa = 0;
290*5f184715SAndy Fleming 
291*5f184715SAndy Fleming 		/* Check for gigabit capability */
292*5f184715SAndy Fleming 		if (mii_reg & BMSR_ERCAP) {
293*5f184715SAndy Fleming 			/* We want a list of states supported by
294*5f184715SAndy Fleming 			 * both PHYs in the link
295*5f184715SAndy Fleming 			 */
296*5f184715SAndy Fleming 			gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
297*5f184715SAndy Fleming 			gblpa &= phy_read(phydev,
298*5f184715SAndy Fleming 					MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
299*5f184715SAndy Fleming 		}
300*5f184715SAndy Fleming 
301*5f184715SAndy Fleming 		/* Set the baseline so we only have to set them
302*5f184715SAndy Fleming 		 * if they're different
303*5f184715SAndy Fleming 		 */
304*5f184715SAndy Fleming 		phydev->speed = SPEED_10;
305*5f184715SAndy Fleming 		phydev->duplex = DUPLEX_HALF;
306*5f184715SAndy Fleming 
307*5f184715SAndy Fleming 		/* Check the gigabit fields */
308*5f184715SAndy Fleming 		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
309*5f184715SAndy Fleming 			phydev->speed = SPEED_1000;
310*5f184715SAndy Fleming 
311*5f184715SAndy Fleming 			if (gblpa & PHY_1000BTSR_1000FD)
312*5f184715SAndy Fleming 				phydev->duplex = DUPLEX_FULL;
313*5f184715SAndy Fleming 
314*5f184715SAndy Fleming 			/* We're done! */
315*5f184715SAndy Fleming 			return 0;
316*5f184715SAndy Fleming 		}
317*5f184715SAndy Fleming 
318*5f184715SAndy Fleming 		lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
319*5f184715SAndy Fleming 		lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
320*5f184715SAndy Fleming 
321*5f184715SAndy Fleming 		if (lpa & (LPA_100FULL | LPA_100HALF)) {
322*5f184715SAndy Fleming 			phydev->speed = SPEED_100;
323*5f184715SAndy Fleming 
324*5f184715SAndy Fleming 			if (lpa & LPA_100FULL)
325*5f184715SAndy Fleming 				phydev->duplex = DUPLEX_FULL;
326*5f184715SAndy Fleming 
327*5f184715SAndy Fleming 		} else if (lpa & LPA_10FULL)
328*5f184715SAndy Fleming 			phydev->duplex = DUPLEX_FULL;
329*5f184715SAndy Fleming 	} else {
330*5f184715SAndy Fleming 		u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
331*5f184715SAndy Fleming 
332*5f184715SAndy Fleming 		phydev->speed = SPEED_10;
333*5f184715SAndy Fleming 		phydev->duplex = DUPLEX_HALF;
334*5f184715SAndy Fleming 
335*5f184715SAndy Fleming 		if (bmcr & BMCR_FULLDPLX)
336*5f184715SAndy Fleming 			phydev->duplex = DUPLEX_FULL;
337*5f184715SAndy Fleming 
338*5f184715SAndy Fleming 		if (bmcr & BMCR_SPEED1000)
339*5f184715SAndy Fleming 			phydev->speed = SPEED_1000;
340*5f184715SAndy Fleming 		else if (bmcr & BMCR_SPEED100)
341*5f184715SAndy Fleming 			phydev->speed = SPEED_100;
342*5f184715SAndy Fleming 	}
343*5f184715SAndy Fleming 
344*5f184715SAndy Fleming 	return 0;
345*5f184715SAndy Fleming }
346*5f184715SAndy Fleming 
347*5f184715SAndy Fleming int genphy_config(struct phy_device *phydev)
348*5f184715SAndy Fleming {
349*5f184715SAndy Fleming 	int val;
350*5f184715SAndy Fleming 	u32 features;
351*5f184715SAndy Fleming 
352*5f184715SAndy Fleming 	/* For now, I'll claim that the generic driver supports
353*5f184715SAndy Fleming 	 * all possible port types */
354*5f184715SAndy Fleming 	features = (SUPPORTED_TP | SUPPORTED_MII
355*5f184715SAndy Fleming 			| SUPPORTED_AUI | SUPPORTED_FIBRE |
356*5f184715SAndy Fleming 			SUPPORTED_BNC);
357*5f184715SAndy Fleming 
358*5f184715SAndy Fleming 	/* Do we support autonegotiation? */
359*5f184715SAndy Fleming 	val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
360*5f184715SAndy Fleming 
361*5f184715SAndy Fleming 	if (val < 0)
362*5f184715SAndy Fleming 		return val;
363*5f184715SAndy Fleming 
364*5f184715SAndy Fleming 	if (val & BMSR_ANEGCAPABLE)
365*5f184715SAndy Fleming 		features |= SUPPORTED_Autoneg;
366*5f184715SAndy Fleming 
367*5f184715SAndy Fleming 	if (val & BMSR_100FULL)
368*5f184715SAndy Fleming 		features |= SUPPORTED_100baseT_Full;
369*5f184715SAndy Fleming 	if (val & BMSR_100HALF)
370*5f184715SAndy Fleming 		features |= SUPPORTED_100baseT_Half;
371*5f184715SAndy Fleming 	if (val & BMSR_10FULL)
372*5f184715SAndy Fleming 		features |= SUPPORTED_10baseT_Full;
373*5f184715SAndy Fleming 	if (val & BMSR_10HALF)
374*5f184715SAndy Fleming 		features |= SUPPORTED_10baseT_Half;
375*5f184715SAndy Fleming 
376*5f184715SAndy Fleming 	if (val & BMSR_ESTATEN) {
377*5f184715SAndy Fleming 		val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);
378*5f184715SAndy Fleming 
379*5f184715SAndy Fleming 		if (val < 0)
380*5f184715SAndy Fleming 			return val;
381*5f184715SAndy Fleming 
382*5f184715SAndy Fleming 		if (val & ESTATUS_1000_TFULL)
383*5f184715SAndy Fleming 			features |= SUPPORTED_1000baseT_Full;
384*5f184715SAndy Fleming 		if (val & ESTATUS_1000_THALF)
385*5f184715SAndy Fleming 			features |= SUPPORTED_1000baseT_Half;
386*5f184715SAndy Fleming 	}
387*5f184715SAndy Fleming 
388*5f184715SAndy Fleming 	phydev->supported = features;
389*5f184715SAndy Fleming 	phydev->advertising = features;
390*5f184715SAndy Fleming 
391*5f184715SAndy Fleming 	genphy_config_aneg(phydev);
392*5f184715SAndy Fleming 
393*5f184715SAndy Fleming 	return 0;
394*5f184715SAndy Fleming }
395*5f184715SAndy Fleming 
396*5f184715SAndy Fleming int genphy_startup(struct phy_device *phydev)
397*5f184715SAndy Fleming {
398*5f184715SAndy Fleming 	genphy_update_link(phydev);
399*5f184715SAndy Fleming 	genphy_parse_link(phydev);
400*5f184715SAndy Fleming 
401*5f184715SAndy Fleming 	return 0;
402*5f184715SAndy Fleming }
403*5f184715SAndy Fleming 
404*5f184715SAndy Fleming int genphy_shutdown(struct phy_device *phydev)
405*5f184715SAndy Fleming {
406*5f184715SAndy Fleming 	return 0;
407*5f184715SAndy Fleming }
408*5f184715SAndy Fleming 
409*5f184715SAndy Fleming static struct phy_driver genphy_driver = {
410*5f184715SAndy Fleming 	.uid		= 0xffffffff,
411*5f184715SAndy Fleming 	.mask		= 0xffffffff,
412*5f184715SAndy Fleming 	.name		= "Generic PHY",
413*5f184715SAndy Fleming 	.features	= 0,
414*5f184715SAndy Fleming 	.config		= genphy_config,
415*5f184715SAndy Fleming 	.startup	= genphy_startup,
416*5f184715SAndy Fleming 	.shutdown	= genphy_shutdown,
417*5f184715SAndy Fleming };
418*5f184715SAndy Fleming 
419*5f184715SAndy Fleming static LIST_HEAD(phy_drivers);
420*5f184715SAndy Fleming 
421*5f184715SAndy Fleming int phy_init(void)
422*5f184715SAndy Fleming {
423*5f184715SAndy Fleming 	return 0;
424*5f184715SAndy Fleming }
425*5f184715SAndy Fleming 
426*5f184715SAndy Fleming int phy_register(struct phy_driver *drv)
427*5f184715SAndy Fleming {
428*5f184715SAndy Fleming 	INIT_LIST_HEAD(&drv->list);
429*5f184715SAndy Fleming 	list_add_tail(&drv->list, &phy_drivers);
430*5f184715SAndy Fleming 
431*5f184715SAndy Fleming 	return 0;
432*5f184715SAndy Fleming }
433*5f184715SAndy Fleming 
434*5f184715SAndy Fleming int phy_probe(struct phy_device *phydev)
435*5f184715SAndy Fleming {
436*5f184715SAndy Fleming 	int err = 0;
437*5f184715SAndy Fleming 
438*5f184715SAndy Fleming 	phydev->advertising = phydev->supported = phydev->drv->features;
439*5f184715SAndy Fleming 	phydev->mmds = phydev->drv->mmds;
440*5f184715SAndy Fleming 
441*5f184715SAndy Fleming 	if (phydev->drv->probe)
442*5f184715SAndy Fleming 		err = phydev->drv->probe(phydev);
443*5f184715SAndy Fleming 
444*5f184715SAndy Fleming 	return err;
445*5f184715SAndy Fleming }
446*5f184715SAndy Fleming 
447*5f184715SAndy Fleming static struct phy_driver *generic_for_interface(phy_interface_t interface)
448*5f184715SAndy Fleming {
449*5f184715SAndy Fleming #ifdef CONFIG_PHYLIB_10G
450*5f184715SAndy Fleming 	if (is_10g_interface(interface))
451*5f184715SAndy Fleming 		return &gen10g_driver;
452*5f184715SAndy Fleming #endif
453*5f184715SAndy Fleming 
454*5f184715SAndy Fleming 	return &genphy_driver;
455*5f184715SAndy Fleming }
456*5f184715SAndy Fleming 
457*5f184715SAndy Fleming struct phy_driver *get_phy_driver(struct phy_device *phydev,
458*5f184715SAndy Fleming 				phy_interface_t interface)
459*5f184715SAndy Fleming {
460*5f184715SAndy Fleming 	struct list_head *entry;
461*5f184715SAndy Fleming 	int phy_id = phydev->phy_id;
462*5f184715SAndy Fleming 	struct phy_driver *drv = NULL;
463*5f184715SAndy Fleming 
464*5f184715SAndy Fleming 	list_for_each(entry, &phy_drivers) {
465*5f184715SAndy Fleming 		drv = list_entry(entry, struct phy_driver, list);
466*5f184715SAndy Fleming 		if ((drv->uid & drv->mask) == (phy_id & drv->mask))
467*5f184715SAndy Fleming 			return drv;
468*5f184715SAndy Fleming 	}
469*5f184715SAndy Fleming 
470*5f184715SAndy Fleming 	/* If we made it here, there's no driver for this PHY */
471*5f184715SAndy Fleming 	return generic_for_interface(interface);
472*5f184715SAndy Fleming }
473*5f184715SAndy Fleming 
474*5f184715SAndy Fleming struct phy_device *phy_device_create(struct mii_dev *bus, int addr, int phy_id,
475*5f184715SAndy Fleming 					phy_interface_t interface)
476*5f184715SAndy Fleming {
477*5f184715SAndy Fleming 	struct phy_device *dev;
478*5f184715SAndy Fleming 
479*5f184715SAndy Fleming 	/* We allocate the device, and initialize the
480*5f184715SAndy Fleming 	 * default values */
481*5f184715SAndy Fleming 	dev = malloc(sizeof(*dev));
482*5f184715SAndy Fleming 	if (!dev) {
483*5f184715SAndy Fleming 		printf("Failed to allocate PHY device for %s:%d\n",
484*5f184715SAndy Fleming 			bus->name, addr);
485*5f184715SAndy Fleming 		return NULL;
486*5f184715SAndy Fleming 	}
487*5f184715SAndy Fleming 
488*5f184715SAndy Fleming 	memset(dev, 0, sizeof(*dev));
489*5f184715SAndy Fleming 
490*5f184715SAndy Fleming 	dev->duplex = -1;
491*5f184715SAndy Fleming 	dev->link = 1;
492*5f184715SAndy Fleming 	dev->interface = interface;
493*5f184715SAndy Fleming 
494*5f184715SAndy Fleming 	dev->autoneg = AUTONEG_ENABLE;
495*5f184715SAndy Fleming 
496*5f184715SAndy Fleming 	dev->addr = addr;
497*5f184715SAndy Fleming 	dev->phy_id = phy_id;
498*5f184715SAndy Fleming 	dev->bus = bus;
499*5f184715SAndy Fleming 
500*5f184715SAndy Fleming 	dev->drv = get_phy_driver(dev, interface);
501*5f184715SAndy Fleming 
502*5f184715SAndy Fleming 	phy_probe(dev);
503*5f184715SAndy Fleming 
504*5f184715SAndy Fleming 	bus->phymap[addr] = dev;
505*5f184715SAndy Fleming 
506*5f184715SAndy Fleming 	return dev;
507*5f184715SAndy Fleming }
508*5f184715SAndy Fleming 
509*5f184715SAndy Fleming /**
510*5f184715SAndy Fleming  * get_phy_id - reads the specified addr for its ID.
511*5f184715SAndy Fleming  * @bus: the target MII bus
512*5f184715SAndy Fleming  * @addr: PHY address on the MII bus
513*5f184715SAndy Fleming  * @phy_id: where to store the ID retrieved.
514*5f184715SAndy Fleming  *
515*5f184715SAndy Fleming  * Description: Reads the ID registers of the PHY at @addr on the
516*5f184715SAndy Fleming  *   @bus, stores it in @phy_id and returns zero on success.
517*5f184715SAndy Fleming  */
518*5f184715SAndy Fleming int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
519*5f184715SAndy Fleming {
520*5f184715SAndy Fleming 	int phy_reg;
521*5f184715SAndy Fleming 
522*5f184715SAndy Fleming 	/* Grab the bits from PHYIR1, and put them
523*5f184715SAndy Fleming 	 * in the upper half */
524*5f184715SAndy Fleming 	phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
525*5f184715SAndy Fleming 
526*5f184715SAndy Fleming 	if (phy_reg < 0)
527*5f184715SAndy Fleming 		return -EIO;
528*5f184715SAndy Fleming 
529*5f184715SAndy Fleming 	*phy_id = (phy_reg & 0xffff) << 16;
530*5f184715SAndy Fleming 
531*5f184715SAndy Fleming 	/* Grab the bits from PHYIR2, and put them in the lower half */
532*5f184715SAndy Fleming 	phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
533*5f184715SAndy Fleming 
534*5f184715SAndy Fleming 	if (phy_reg < 0)
535*5f184715SAndy Fleming 		return -EIO;
536*5f184715SAndy Fleming 
537*5f184715SAndy Fleming 	*phy_id |= (phy_reg & 0xffff);
538*5f184715SAndy Fleming 
539*5f184715SAndy Fleming 	return 0;
540*5f184715SAndy Fleming }
541*5f184715SAndy Fleming 
542*5f184715SAndy Fleming /**
543*5f184715SAndy Fleming  * get_phy_device - reads the specified PHY device and returns its @phy_device struct
544*5f184715SAndy Fleming  * @bus: the target MII bus
545*5f184715SAndy Fleming  * @addr: PHY address on the MII bus
546*5f184715SAndy Fleming  *
547*5f184715SAndy Fleming  * Description: Reads the ID registers of the PHY at @addr on the
548*5f184715SAndy Fleming  *   @bus, then allocates and returns the phy_device to represent it.
549*5f184715SAndy Fleming  */
550*5f184715SAndy Fleming struct phy_device *get_phy_device(struct mii_dev *bus, int addr,
551*5f184715SAndy Fleming 				phy_interface_t interface)
552*5f184715SAndy Fleming {
553*5f184715SAndy Fleming 	u32 phy_id = 0x1fffffff;
554*5f184715SAndy Fleming 	int i;
555*5f184715SAndy Fleming 	int r;
556*5f184715SAndy Fleming 
557*5f184715SAndy Fleming 	/* If we have one, return the existing device, with new interface */
558*5f184715SAndy Fleming 	if (bus->phymap[addr]) {
559*5f184715SAndy Fleming 		bus->phymap[addr]->interface = interface;
560*5f184715SAndy Fleming 
561*5f184715SAndy Fleming 		return bus->phymap[addr];
562*5f184715SAndy Fleming 	}
563*5f184715SAndy Fleming 
564*5f184715SAndy Fleming 	/* Try Standard (ie Clause 22) access */
565*5f184715SAndy Fleming 	r = get_phy_id(bus, addr, MDIO_DEVAD_NONE, &phy_id);
566*5f184715SAndy Fleming 	if (r)
567*5f184715SAndy Fleming 		return NULL;
568*5f184715SAndy Fleming 
569*5f184715SAndy Fleming 	/* If the PHY ID is mostly f's, we didn't find anything */
570*5f184715SAndy Fleming 	if ((phy_id & 0x1fffffff) != 0x1fffffff)
571*5f184715SAndy Fleming 		return phy_device_create(bus, addr, phy_id, interface);
572*5f184715SAndy Fleming 
573*5f184715SAndy Fleming 	/* Otherwise we have to try Clause 45 */
574*5f184715SAndy Fleming 	for (i = 1; i < 5; i++) {
575*5f184715SAndy Fleming 		r = get_phy_id(bus, addr, i, &phy_id);
576*5f184715SAndy Fleming 		if (r)
577*5f184715SAndy Fleming 			return NULL;
578*5f184715SAndy Fleming 
579*5f184715SAndy Fleming 		/* If the phy_id is mostly Fs, there is no device there */
580*5f184715SAndy Fleming 		if ((phy_id & 0x1fffffff) != 0x1fffffff)
581*5f184715SAndy Fleming 			break;
582*5f184715SAndy Fleming 	}
583*5f184715SAndy Fleming 
584*5f184715SAndy Fleming 	return phy_device_create(bus, addr, phy_id, interface);
585*5f184715SAndy Fleming }
586*5f184715SAndy Fleming 
587*5f184715SAndy Fleming int phy_reset(struct phy_device *phydev)
588*5f184715SAndy Fleming {
589*5f184715SAndy Fleming 	int reg;
590*5f184715SAndy Fleming 	int timeout = 500;
591*5f184715SAndy Fleming 	int devad = MDIO_DEVAD_NONE;
592*5f184715SAndy Fleming 
593*5f184715SAndy Fleming #ifdef CONFIG_PHYLIB_10G
594*5f184715SAndy Fleming 	/* If it's 10G, we need to issue reset through one of the MMDs */
595*5f184715SAndy Fleming 	if (is_10g_interface(phydev->interface)) {
596*5f184715SAndy Fleming 		if (!phydev->mmds)
597*5f184715SAndy Fleming 			gen10g_discover_mmds(phydev);
598*5f184715SAndy Fleming 
599*5f184715SAndy Fleming 		devad = ffs(phydev->mmds) - 1;
600*5f184715SAndy Fleming 	}
601*5f184715SAndy Fleming #endif
602*5f184715SAndy Fleming 
603*5f184715SAndy Fleming 	reg = phy_read(phydev, devad, MII_BMCR);
604*5f184715SAndy Fleming 	if (reg < 0) {
605*5f184715SAndy Fleming 		debug("PHY status read failed\n");
606*5f184715SAndy Fleming 		return -1;
607*5f184715SAndy Fleming 	}
608*5f184715SAndy Fleming 
609*5f184715SAndy Fleming 	reg |= BMCR_RESET;
610*5f184715SAndy Fleming 
611*5f184715SAndy Fleming 	if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
612*5f184715SAndy Fleming 		debug("PHY reset failed\n");
613*5f184715SAndy Fleming 		return -1;
614*5f184715SAndy Fleming 	}
615*5f184715SAndy Fleming 
616*5f184715SAndy Fleming #ifdef CONFIG_PHY_RESET_DELAY
617*5f184715SAndy Fleming 	udelay(CONFIG_PHY_RESET_DELAY);	/* Intel LXT971A needs this */
618*5f184715SAndy Fleming #endif
619*5f184715SAndy Fleming 	/*
620*5f184715SAndy Fleming 	 * Poll the control register for the reset bit to go to 0 (it is
621*5f184715SAndy Fleming 	 * auto-clearing).  This should happen within 0.5 seconds per the
622*5f184715SAndy Fleming 	 * IEEE spec.
623*5f184715SAndy Fleming 	 */
624*5f184715SAndy Fleming 	while ((reg & BMCR_RESET) && timeout--) {
625*5f184715SAndy Fleming 		reg = phy_read(phydev, devad, MII_BMCR);
626*5f184715SAndy Fleming 
627*5f184715SAndy Fleming 		if (reg < 0) {
628*5f184715SAndy Fleming 			debug("PHY status read failed\n");
629*5f184715SAndy Fleming 			return -1;
630*5f184715SAndy Fleming 		}
631*5f184715SAndy Fleming 		udelay(1000);
632*5f184715SAndy Fleming 	}
633*5f184715SAndy Fleming 
634*5f184715SAndy Fleming 	if (reg & BMCR_RESET) {
635*5f184715SAndy Fleming 		puts("PHY reset timed out\n");
636*5f184715SAndy Fleming 		return -1;
637*5f184715SAndy Fleming 	}
638*5f184715SAndy Fleming 
639*5f184715SAndy Fleming 	return 0;
640*5f184715SAndy Fleming }
641*5f184715SAndy Fleming 
642*5f184715SAndy Fleming int miiphy_reset(const char *devname, unsigned char addr)
643*5f184715SAndy Fleming {
644*5f184715SAndy Fleming 	struct mii_dev *bus = miiphy_get_dev_by_name(devname);
645*5f184715SAndy Fleming 	struct phy_device *phydev;
646*5f184715SAndy Fleming 
647*5f184715SAndy Fleming 	/*
648*5f184715SAndy Fleming 	 * miiphy_reset was only used on standard PHYs, so we'll fake it here.
649*5f184715SAndy Fleming 	 * If later code tries to connect with the right interface, this will
650*5f184715SAndy Fleming 	 * be corrected by get_phy_device in phy_connect()
651*5f184715SAndy Fleming 	 */
652*5f184715SAndy Fleming 	phydev = get_phy_device(bus, addr, PHY_INTERFACE_MODE_MII);
653*5f184715SAndy Fleming 
654*5f184715SAndy Fleming 	return phy_reset(phydev);
655*5f184715SAndy Fleming }
656*5f184715SAndy Fleming 
657*5f184715SAndy Fleming struct phy_device *phy_connect(struct mii_dev *bus, int addr,
658*5f184715SAndy Fleming 				struct eth_device *dev,
659*5f184715SAndy Fleming 				phy_interface_t interface)
660*5f184715SAndy Fleming {
661*5f184715SAndy Fleming 	struct phy_device *phydev;
662*5f184715SAndy Fleming 
663*5f184715SAndy Fleming 	/* Reset the bus */
664*5f184715SAndy Fleming 	bus->reset(bus);
665*5f184715SAndy Fleming 
666*5f184715SAndy Fleming 	/* Wait 15ms to make sure the PHY has come out of hard reset */
667*5f184715SAndy Fleming 	udelay(15000);
668*5f184715SAndy Fleming 
669*5f184715SAndy Fleming 	phydev = get_phy_device(bus, addr, interface);
670*5f184715SAndy Fleming 
671*5f184715SAndy Fleming 	if (!phydev) {
672*5f184715SAndy Fleming 		printf("Could not get PHY for %s:%d\n", bus->name, addr);
673*5f184715SAndy Fleming 
674*5f184715SAndy Fleming 		return NULL;
675*5f184715SAndy Fleming 	}
676*5f184715SAndy Fleming 
677*5f184715SAndy Fleming 	/* Soft Reset the PHY */
678*5f184715SAndy Fleming 	phy_reset(phydev);
679*5f184715SAndy Fleming 
680*5f184715SAndy Fleming 	if (phydev->dev)
681*5f184715SAndy Fleming 		printf("%s:%d is connected to %s.  Reconnecting to %s\n",
682*5f184715SAndy Fleming 			bus->name, addr, phydev->dev->name, dev->name);
683*5f184715SAndy Fleming 
684*5f184715SAndy Fleming 	phydev->dev = dev;
685*5f184715SAndy Fleming 
686*5f184715SAndy Fleming 	printf("%s connected to %s\n", dev->name, phydev->drv->name);
687*5f184715SAndy Fleming 
688*5f184715SAndy Fleming 	return phydev;
689*5f184715SAndy Fleming }
690*5f184715SAndy Fleming 
691*5f184715SAndy Fleming int phy_startup(struct phy_device *phydev)
692*5f184715SAndy Fleming {
693*5f184715SAndy Fleming 	if (phydev->drv->startup)
694*5f184715SAndy Fleming 		phydev->drv->startup(phydev);
695*5f184715SAndy Fleming 
696*5f184715SAndy Fleming 	return 0;
697*5f184715SAndy Fleming }
698*5f184715SAndy Fleming 
699*5f184715SAndy Fleming static int __board_phy_config(struct phy_device *phydev)
700*5f184715SAndy Fleming {
701*5f184715SAndy Fleming 	return 0;
702*5f184715SAndy Fleming }
703*5f184715SAndy Fleming 
704*5f184715SAndy Fleming int board_phy_config(struct phy_device *phydev)
705*5f184715SAndy Fleming 	__attribute__((weak, alias("__board_phy_config")));
706*5f184715SAndy Fleming 
707*5f184715SAndy Fleming int phy_config(struct phy_device *phydev)
708*5f184715SAndy Fleming {
709*5f184715SAndy Fleming 	if (phydev->drv->config)
710*5f184715SAndy Fleming 		phydev->drv->config(phydev);
711*5f184715SAndy Fleming 
712*5f184715SAndy Fleming 	/* Invoke an optional board-specific helper */
713*5f184715SAndy Fleming 	board_phy_config(phydev);
714*5f184715SAndy Fleming 
715*5f184715SAndy Fleming 	return 0;
716*5f184715SAndy Fleming }
717*5f184715SAndy Fleming 
718*5f184715SAndy Fleming int phy_shutdown(struct phy_device *phydev)
719*5f184715SAndy Fleming {
720*5f184715SAndy Fleming 	if (phydev->drv->shutdown)
721*5f184715SAndy Fleming 		phydev->drv->shutdown(phydev);
722*5f184715SAndy Fleming 
723*5f184715SAndy Fleming 	return 0;
724*5f184715SAndy Fleming }
725