[PATCH] New PowerPC 4xx on-chip ethernet controller driver
[linux-2.6.git] / drivers / net / ibm_emac / ibm_emac_phy.c
bloba27e49cfe43be657f8d6610504fd36d26b8a7003
1 /*
2 * drivers/net/ibm_emac/ibm_emac_phy.c
4 * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
5 * Borrowed from sungem_phy.c, though I only kept the generic MII
6 * driver for now.
7 *
8 * This file should be shared with other drivers or eventually
9 * merged as the "low level" part of miilib
11 * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
12 * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
15 #include <linux/config.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/types.h>
19 #include <linux/netdevice.h>
20 #include <linux/mii.h>
21 #include <linux/ethtool.h>
22 #include <linux/delay.h>
24 #include <asm/ocp.h>
26 #include "ibm_emac_phy.h"
28 static inline int phy_read(struct mii_phy *phy, int reg)
30 return phy->mdio_read(phy->dev, phy->address, reg);
33 static inline void phy_write(struct mii_phy *phy, int reg, int val)
35 phy->mdio_write(phy->dev, phy->address, reg, val);
38 int mii_reset_phy(struct mii_phy *phy)
40 int val;
41 int limit = 10000;
43 val = phy_read(phy, MII_BMCR);
44 val &= ~BMCR_ISOLATE;
45 val |= BMCR_RESET;
46 phy_write(phy, MII_BMCR, val);
48 udelay(300);
50 while (limit--) {
51 val = phy_read(phy, MII_BMCR);
52 if (val >= 0 && (val & BMCR_RESET) == 0)
53 break;
54 udelay(10);
56 if ((val & BMCR_ISOLATE) && limit > 0)
57 phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
59 return limit <= 0;
62 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
64 int ctl, adv;
66 phy->autoneg = AUTONEG_ENABLE;
67 phy->speed = SPEED_10;
68 phy->duplex = DUPLEX_HALF;
69 phy->pause = phy->asym_pause = 0;
70 phy->advertising = advertise;
72 /* Setup standard advertise */
73 adv = phy_read(phy, MII_ADVERTISE);
74 if (adv < 0)
75 return adv;
76 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
77 ADVERTISE_PAUSE_ASYM);
78 if (advertise & ADVERTISED_10baseT_Half)
79 adv |= ADVERTISE_10HALF;
80 if (advertise & ADVERTISED_10baseT_Full)
81 adv |= ADVERTISE_10FULL;
82 if (advertise & ADVERTISED_100baseT_Half)
83 adv |= ADVERTISE_100HALF;
84 if (advertise & ADVERTISED_100baseT_Full)
85 adv |= ADVERTISE_100FULL;
86 if (advertise & ADVERTISED_Pause)
87 adv |= ADVERTISE_PAUSE_CAP;
88 if (advertise & ADVERTISED_Asym_Pause)
89 adv |= ADVERTISE_PAUSE_ASYM;
90 phy_write(phy, MII_ADVERTISE, adv);
92 if (phy->features &
93 (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
94 adv = phy_read(phy, MII_CTRL1000);
95 if (adv < 0)
96 return adv;
97 adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
98 if (advertise & ADVERTISED_1000baseT_Full)
99 adv |= ADVERTISE_1000FULL;
100 if (advertise & ADVERTISED_1000baseT_Half)
101 adv |= ADVERTISE_1000HALF;
102 phy_write(phy, MII_CTRL1000, adv);
105 /* Start/Restart aneg */
106 ctl = phy_read(phy, MII_BMCR);
107 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
108 phy_write(phy, MII_BMCR, ctl);
110 return 0;
113 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
115 int ctl;
117 phy->autoneg = AUTONEG_DISABLE;
118 phy->speed = speed;
119 phy->duplex = fd;
120 phy->pause = phy->asym_pause = 0;
122 ctl = phy_read(phy, MII_BMCR);
123 if (ctl < 0)
124 return ctl;
125 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
127 /* First reset the PHY */
128 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
130 /* Select speed & duplex */
131 switch (speed) {
132 case SPEED_10:
133 break;
134 case SPEED_100:
135 ctl |= BMCR_SPEED100;
136 break;
137 case SPEED_1000:
138 ctl |= BMCR_SPEED1000;
139 break;
140 default:
141 return -EINVAL;
143 if (fd == DUPLEX_FULL)
144 ctl |= BMCR_FULLDPLX;
145 phy_write(phy, MII_BMCR, ctl);
147 return 0;
150 static int genmii_poll_link(struct mii_phy *phy)
152 int status;
154 /* Clear latched value with dummy read */
155 phy_read(phy, MII_BMSR);
156 status = phy_read(phy, MII_BMSR);
157 if (status < 0 || (status & BMSR_LSTATUS) == 0)
158 return 0;
159 if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
160 return 0;
161 return 1;
164 static int genmii_read_link(struct mii_phy *phy)
166 if (phy->autoneg == AUTONEG_ENABLE) {
167 int glpa = 0;
168 int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
169 if (lpa < 0)
170 return lpa;
172 if (phy->features &
173 (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
174 int adv = phy_read(phy, MII_CTRL1000);
175 glpa = phy_read(phy, MII_STAT1000);
177 if (glpa < 0 || adv < 0)
178 return adv;
180 glpa &= adv << 2;
183 phy->speed = SPEED_10;
184 phy->duplex = DUPLEX_HALF;
185 phy->pause = phy->asym_pause = 0;
187 if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
188 phy->speed = SPEED_1000;
189 if (glpa & LPA_1000FULL)
190 phy->duplex = DUPLEX_FULL;
191 } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
192 phy->speed = SPEED_100;
193 if (lpa & LPA_100FULL)
194 phy->duplex = DUPLEX_FULL;
195 } else if (lpa & LPA_10FULL)
196 phy->duplex = DUPLEX_FULL;
198 if (phy->duplex == DUPLEX_FULL) {
199 phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
200 phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
202 } else {
203 int bmcr = phy_read(phy, MII_BMCR);
204 if (bmcr < 0)
205 return bmcr;
207 if (bmcr & BMCR_FULLDPLX)
208 phy->duplex = DUPLEX_FULL;
209 else
210 phy->duplex = DUPLEX_HALF;
211 if (bmcr & BMCR_SPEED1000)
212 phy->speed = SPEED_1000;
213 else if (bmcr & BMCR_SPEED100)
214 phy->speed = SPEED_100;
215 else
216 phy->speed = SPEED_10;
218 phy->pause = phy->asym_pause = 0;
220 return 0;
223 /* Generic implementation for most 10/100/1000 PHYs */
224 static struct mii_phy_ops generic_phy_ops = {
225 .setup_aneg = genmii_setup_aneg,
226 .setup_forced = genmii_setup_forced,
227 .poll_link = genmii_poll_link,
228 .read_link = genmii_read_link
231 static struct mii_phy_def genmii_phy_def = {
232 .phy_id = 0x00000000,
233 .phy_id_mask = 0x00000000,
234 .name = "Generic MII",
235 .ops = &generic_phy_ops
238 /* CIS8201 */
239 #define MII_CIS8201_EPCR 0x17
240 #define EPCR_MODE_MASK 0x3000
241 #define EPCR_GMII_MODE 0x0000
242 #define EPCR_RGMII_MODE 0x1000
243 #define EPCR_TBI_MODE 0x2000
244 #define EPCR_RTBI_MODE 0x3000
246 static int cis8201_init(struct mii_phy *phy)
248 int epcr;
250 epcr = phy_read(phy, MII_CIS8201_EPCR);
251 if (epcr < 0)
252 return epcr;
254 epcr &= ~EPCR_MODE_MASK;
256 switch (phy->mode) {
257 case PHY_MODE_TBI:
258 epcr |= EPCR_TBI_MODE;
259 break;
260 case PHY_MODE_RTBI:
261 epcr |= EPCR_RTBI_MODE;
262 break;
263 case PHY_MODE_GMII:
264 epcr |= EPCR_GMII_MODE;
265 break;
266 case PHY_MODE_RGMII:
267 default:
268 epcr |= EPCR_RGMII_MODE;
271 phy_write(phy, MII_CIS8201_EPCR, epcr);
273 return 0;
276 static struct mii_phy_ops cis8201_phy_ops = {
277 .init = cis8201_init,
278 .setup_aneg = genmii_setup_aneg,
279 .setup_forced = genmii_setup_forced,
280 .poll_link = genmii_poll_link,
281 .read_link = genmii_read_link
284 static struct mii_phy_def cis8201_phy_def = {
285 .phy_id = 0x000fc410,
286 .phy_id_mask = 0x000ffff0,
287 .name = "CIS8201 Gigabit Ethernet",
288 .ops = &cis8201_phy_ops
291 static struct mii_phy_def *mii_phy_table[] = {
292 &cis8201_phy_def,
293 &genmii_phy_def,
294 NULL
297 int mii_phy_probe(struct mii_phy *phy, int address)
299 struct mii_phy_def *def;
300 int i;
301 u32 id;
303 phy->autoneg = AUTONEG_DISABLE;
304 phy->advertising = 0;
305 phy->address = address;
306 phy->speed = SPEED_10;
307 phy->duplex = DUPLEX_HALF;
308 phy->pause = phy->asym_pause = 0;
310 /* Take PHY out of isolate mode and reset it. */
311 if (mii_reset_phy(phy))
312 return -ENODEV;
314 /* Read ID and find matching entry */
315 id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
316 for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
317 if ((id & def->phy_id_mask) == def->phy_id)
318 break;
319 /* Should never be NULL (we have a generic entry), but... */
320 if (!def)
321 return -ENODEV;
323 phy->def = def;
325 /* Determine PHY features if needed */
326 phy->features = def->features;
327 if (!phy->features) {
328 u16 bmsr = phy_read(phy, MII_BMSR);
329 if (bmsr & BMSR_ANEGCAPABLE)
330 phy->features |= SUPPORTED_Autoneg;
331 if (bmsr & BMSR_10HALF)
332 phy->features |= SUPPORTED_10baseT_Half;
333 if (bmsr & BMSR_10FULL)
334 phy->features |= SUPPORTED_10baseT_Full;
335 if (bmsr & BMSR_100HALF)
336 phy->features |= SUPPORTED_100baseT_Half;
337 if (bmsr & BMSR_100FULL)
338 phy->features |= SUPPORTED_100baseT_Full;
339 if (bmsr & BMSR_ESTATEN) {
340 u16 esr = phy_read(phy, MII_ESTATUS);
341 if (esr & ESTATUS_1000_TFULL)
342 phy->features |= SUPPORTED_1000baseT_Full;
343 if (esr & ESTATUS_1000_THALF)
344 phy->features |= SUPPORTED_1000baseT_Half;
346 phy->features |= SUPPORTED_MII;
349 /* Setup default advertising */
350 phy->advertising = phy->features;
352 return 0;
355 MODULE_LICENSE("GPL");