xref: /openbmc/u-boot/drivers/net/phy/realtek.c (revision 9b914727)
1 /*
2  * RealTek PHY drivers
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307 USA
18  *
19  * Copyright 2010-2011 Freescale Semiconductor, Inc.
20  * author Andy Fleming
21  *
22  */
23 #include <config.h>
24 #include <common.h>
25 #include <phy.h>
26 
27 #define PHY_AUTONEGOTIATE_TIMEOUT 5000
28 
29 /* RTL8211B PHY Status Register */
30 #define MIIM_RTL8211B_PHY_STATUS       0x11
31 #define MIIM_RTL8211B_PHYSTAT_SPEED    0xc000
32 #define MIIM_RTL8211B_PHYSTAT_GBIT     0x8000
33 #define MIIM_RTL8211B_PHYSTAT_100      0x4000
34 #define MIIM_RTL8211B_PHYSTAT_DUPLEX   0x2000
35 #define MIIM_RTL8211B_PHYSTAT_SPDDONE  0x0800
36 #define MIIM_RTL8211B_PHYSTAT_LINK     0x0400
37 
38 
39 /* RealTek RTL8211B */
40 static int rtl8211b_config(struct phy_device *phydev)
41 {
42 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
43 
44 	genphy_config_aneg(phydev);
45 
46 	return 0;
47 }
48 
49 static int rtl8211b_parse_status(struct phy_device *phydev)
50 {
51 	unsigned int speed;
52 	unsigned int mii_reg;
53 
54 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211B_PHY_STATUS);
55 
56 	if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
57 		int i = 0;
58 
59 		/* in case of timeout ->link is cleared */
60 		phydev->link = 1;
61 		puts("Waiting for PHY realtime link");
62 		while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
63 			/* Timeout reached ? */
64 			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
65 				puts(" TIMEOUT !\n");
66 				phydev->link = 0;
67 				break;
68 			}
69 
70 			if ((i++ % 1000) == 0)
71 				putc('.');
72 			udelay(1000);	/* 1 ms */
73 			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
74 					MIIM_RTL8211B_PHY_STATUS);
75 		}
76 		puts(" done\n");
77 		udelay(500000);	/* another 500 ms (results in faster booting) */
78 	} else {
79 		if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
80 			phydev->link = 1;
81 		else
82 			phydev->link = 0;
83 	}
84 
85 	if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
86 		phydev->duplex = DUPLEX_FULL;
87 	else
88 		phydev->duplex = DUPLEX_HALF;
89 
90 	speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
91 
92 	switch (speed) {
93 	case MIIM_RTL8211B_PHYSTAT_GBIT:
94 		phydev->speed = SPEED_1000;
95 		break;
96 	case MIIM_RTL8211B_PHYSTAT_100:
97 		phydev->speed = SPEED_100;
98 		break;
99 	default:
100 		phydev->speed = SPEED_10;
101 	}
102 
103 	return 0;
104 }
105 
106 static int rtl8211b_startup(struct phy_device *phydev)
107 {
108 	/* Read the Status (2x to make sure link is right) */
109 	genphy_update_link(phydev);
110 	rtl8211b_parse_status(phydev);
111 
112 	return 0;
113 }
114 
115 static struct phy_driver RTL8211B_driver = {
116 	.name = "RealTek RTL8211B",
117 	.uid = 0x1cc910,
118 	.mask = 0xfffff0,
119 	.features = PHY_GBIT_FEATURES,
120 	.config = &rtl8211b_config,
121 	.startup = &rtl8211b_startup,
122 	.shutdown = &genphy_shutdown,
123 };
124 
125 int phy_realtek_init(void)
126 {
127 	phy_register(&RTL8211B_driver);
128 
129 	return 0;
130 }
131