diff options
Diffstat (limited to 'drivers/net/fec_8xx/fec_mii.c')
-rw-r--r-- | drivers/net/fec_8xx/fec_mii.c | 418 |
1 files changed, 0 insertions, 418 deletions
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c deleted file mode 100644 index 3b6ca29d31f2..000000000000 --- a/drivers/net/fec_8xx/fec_mii.c +++ /dev/null | |||
@@ -1,418 +0,0 @@ | |||
1 | /* | ||
2 | * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> | ||
8 | * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> | ||
9 | * | ||
10 | * Released under the GPL | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/ptrace.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/etherdevice.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/mii.h> | ||
29 | #include <linux/ethtool.h> | ||
30 | #include <linux/bitops.h> | ||
31 | |||
32 | #include <asm/8xx_immap.h> | ||
33 | #include <asm/pgtable.h> | ||
34 | #include <asm/mpc8xx.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/cpm1.h> | ||
38 | |||
39 | /*************************************************/ | ||
40 | |||
41 | #include "fec_8xx.h" | ||
42 | |||
43 | /*************************************************/ | ||
44 | |||
45 | /* Make MII read/write commands for the FEC. | ||
46 | */ | ||
47 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
48 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
49 | #define mk_mii_end 0 | ||
50 | |||
51 | /*************************************************/ | ||
52 | |||
53 | /* XXX both FECs use the MII interface of FEC1 */ | ||
54 | static DEFINE_SPINLOCK(fec_mii_lock); | ||
55 | |||
56 | #define FEC_MII_LOOPS 10000 | ||
57 | |||
58 | int fec_mii_read(struct net_device *dev, int phy_id, int location) | ||
59 | { | ||
60 | struct fec_enet_private *fep = netdev_priv(dev); | ||
61 | fec_t *fecp; | ||
62 | int i, ret = -1; | ||
63 | unsigned long flags; | ||
64 | |||
65 | /* XXX MII interface is only connected to FEC1 */ | ||
66 | fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec; | ||
67 | |||
68 | spin_lock_irqsave(&fec_mii_lock, flags); | ||
69 | |||
70 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) { | ||
71 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
72 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
73 | FW(fecp, ievent, FEC_ENET_MII); | ||
74 | } | ||
75 | |||
76 | /* Add PHY address to register command. */ | ||
77 | FW(fecp, mii_speed, fep->fec_phy_speed); | ||
78 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
79 | |||
80 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
81 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
82 | break; | ||
83 | |||
84 | if (i < FEC_MII_LOOPS) { | ||
85 | FW(fecp, ievent, FEC_ENET_MII); | ||
86 | ret = FR(fecp, mii_data) & 0xffff; | ||
87 | } | ||
88 | |||
89 | spin_unlock_irqrestore(&fec_mii_lock, flags); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | void fec_mii_write(struct net_device *dev, int phy_id, int location, int value) | ||
95 | { | ||
96 | struct fec_enet_private *fep = netdev_priv(dev); | ||
97 | fec_t *fecp; | ||
98 | unsigned long flags; | ||
99 | int i; | ||
100 | |||
101 | /* XXX MII interface is only connected to FEC1 */ | ||
102 | fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec; | ||
103 | |||
104 | spin_lock_irqsave(&fec_mii_lock, flags); | ||
105 | |||
106 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) { | ||
107 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
108 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
109 | FW(fecp, ievent, FEC_ENET_MII); | ||
110 | } | ||
111 | |||
112 | /* Add PHY address to register command. */ | ||
113 | FW(fecp, mii_speed, fep->fec_phy_speed); /* always adapt mii speed */ | ||
114 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); | ||
115 | |||
116 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
117 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
118 | break; | ||
119 | |||
120 | if (i < FEC_MII_LOOPS) | ||
121 | FW(fecp, ievent, FEC_ENET_MII); | ||
122 | |||
123 | spin_unlock_irqrestore(&fec_mii_lock, flags); | ||
124 | } | ||
125 | |||
126 | /*************************************************/ | ||
127 | |||
128 | #ifdef CONFIG_FEC_8XX_GENERIC_PHY | ||
129 | |||
130 | /* | ||
131 | * Generic PHY support. | ||
132 | * Should work for all PHYs, but link change is detected by polling | ||
133 | */ | ||
134 | |||
135 | static void generic_timer_callback(unsigned long data) | ||
136 | { | ||
137 | struct net_device *dev = (struct net_device *)data; | ||
138 | struct fec_enet_private *fep = netdev_priv(dev); | ||
139 | |||
140 | fep->phy_timer_list.expires = jiffies + HZ / 2; | ||
141 | |||
142 | add_timer(&fep->phy_timer_list); | ||
143 | |||
144 | fec_mii_link_status_change_check(dev, 0); | ||
145 | } | ||
146 | |||
147 | static void generic_startup(struct net_device *dev) | ||
148 | { | ||
149 | struct fec_enet_private *fep = netdev_priv(dev); | ||
150 | |||
151 | fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ | ||
152 | fep->phy_timer_list.data = (unsigned long)dev; | ||
153 | fep->phy_timer_list.function = generic_timer_callback; | ||
154 | add_timer(&fep->phy_timer_list); | ||
155 | } | ||
156 | |||
157 | static void generic_shutdown(struct net_device *dev) | ||
158 | { | ||
159 | struct fec_enet_private *fep = netdev_priv(dev); | ||
160 | |||
161 | del_timer_sync(&fep->phy_timer_list); | ||
162 | } | ||
163 | |||
164 | #endif | ||
165 | |||
166 | #ifdef CONFIG_FEC_8XX_DM9161_PHY | ||
167 | |||
168 | /* ------------------------------------------------------------------------- */ | ||
169 | /* The Davicom DM9161 is used on the NETTA board */ | ||
170 | |||
171 | /* register definitions */ | ||
172 | |||
173 | #define MII_DM9161_ACR 16 /* Aux. Config Register */ | ||
174 | #define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ | ||
175 | #define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ | ||
176 | #define MII_DM9161_INTR 21 /* Interrupt Register */ | ||
177 | #define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ | ||
178 | #define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ | ||
179 | |||
180 | static void dm9161_startup(struct net_device *dev) | ||
181 | { | ||
182 | struct fec_enet_private *fep = netdev_priv(dev); | ||
183 | |||
184 | fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); | ||
185 | } | ||
186 | |||
187 | static void dm9161_ack_int(struct net_device *dev) | ||
188 | { | ||
189 | struct fec_enet_private *fep = netdev_priv(dev); | ||
190 | |||
191 | fec_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); | ||
192 | } | ||
193 | |||
194 | static void dm9161_shutdown(struct net_device *dev) | ||
195 | { | ||
196 | struct fec_enet_private *fep = netdev_priv(dev); | ||
197 | |||
198 | fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); | ||
199 | } | ||
200 | |||
201 | #endif | ||
202 | |||
203 | #ifdef CONFIG_FEC_8XX_LXT971_PHY | ||
204 | |||
205 | /* Support for LXT971/972 PHY */ | ||
206 | |||
207 | #define MII_LXT971_PCR 16 /* Port Control Register */ | ||
208 | #define MII_LXT971_SR2 17 /* Status Register 2 */ | ||
209 | #define MII_LXT971_IER 18 /* Interrupt Enable Register */ | ||
210 | #define MII_LXT971_ISR 19 /* Interrupt Status Register */ | ||
211 | #define MII_LXT971_LCR 20 /* LED Control Register */ | ||
212 | #define MII_LXT971_TCR 30 /* Transmit Control Register */ | ||
213 | |||
214 | static void lxt971_startup(struct net_device *dev) | ||
215 | { | ||
216 | struct fec_enet_private *fep = netdev_priv(dev); | ||
217 | |||
218 | fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x00F2); | ||
219 | } | ||
220 | |||
221 | static void lxt971_ack_int(struct net_device *dev) | ||
222 | { | ||
223 | struct fec_enet_private *fep = netdev_priv(dev); | ||
224 | |||
225 | fec_mii_read(dev, fep->mii_if.phy_id, MII_LXT971_ISR); | ||
226 | } | ||
227 | |||
228 | static void lxt971_shutdown(struct net_device *dev) | ||
229 | { | ||
230 | struct fec_enet_private *fep = netdev_priv(dev); | ||
231 | |||
232 | fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x0000); | ||
233 | } | ||
234 | #endif | ||
235 | |||
236 | /**********************************************************************************/ | ||
237 | |||
238 | static const struct phy_info phy_info[] = { | ||
239 | #ifdef CONFIG_FEC_8XX_DM9161_PHY | ||
240 | { | ||
241 | .id = 0x00181b88, | ||
242 | .name = "DM9161", | ||
243 | .startup = dm9161_startup, | ||
244 | .ack_int = dm9161_ack_int, | ||
245 | .shutdown = dm9161_shutdown, | ||
246 | }, | ||
247 | #endif | ||
248 | #ifdef CONFIG_FEC_8XX_LXT971_PHY | ||
249 | { | ||
250 | .id = 0x0001378e, | ||
251 | .name = "LXT971/972", | ||
252 | .startup = lxt971_startup, | ||
253 | .ack_int = lxt971_ack_int, | ||
254 | .shutdown = lxt971_shutdown, | ||
255 | }, | ||
256 | #endif | ||
257 | #ifdef CONFIG_FEC_8XX_GENERIC_PHY | ||
258 | { | ||
259 | .id = 0, | ||
260 | .name = "GENERIC", | ||
261 | .startup = generic_startup, | ||
262 | .shutdown = generic_shutdown, | ||
263 | }, | ||
264 | #endif | ||
265 | }; | ||
266 | |||
267 | /**********************************************************************************/ | ||
268 | |||
269 | int fec_mii_phy_id_detect(struct net_device *dev) | ||
270 | { | ||
271 | struct fec_enet_private *fep = netdev_priv(dev); | ||
272 | const struct fec_platform_info *fpi = fep->fpi; | ||
273 | int i, r, start, end, phytype, physubtype; | ||
274 | const struct phy_info *phy; | ||
275 | int phy_hwid, phy_id; | ||
276 | |||
277 | /* if no MDIO */ | ||
278 | if (fpi->use_mdio == 0) | ||
279 | return -1; | ||
280 | |||
281 | phy_hwid = -1; | ||
282 | fep->phy = NULL; | ||
283 | |||
284 | /* auto-detect? */ | ||
285 | if (fpi->phy_addr == -1) { | ||
286 | start = 0; | ||
287 | end = 32; | ||
288 | } else { /* direct */ | ||
289 | start = fpi->phy_addr; | ||
290 | end = start + 1; | ||
291 | } | ||
292 | |||
293 | for (phy_id = start; phy_id < end; phy_id++) { | ||
294 | r = fec_mii_read(dev, phy_id, MII_PHYSID1); | ||
295 | if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) | ||
296 | continue; | ||
297 | r = fec_mii_read(dev, phy_id, MII_PHYSID2); | ||
298 | if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) | ||
299 | continue; | ||
300 | phy_hwid = (phytype << 16) | physubtype; | ||
301 | if (phy_hwid != -1) | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | if (phy_hwid == -1) { | ||
306 | printk(KERN_ERR DRV_MODULE_NAME | ||
307 | ": %s No PHY detected!\n", dev->name); | ||
308 | return -1; | ||
309 | } | ||
310 | |||
311 | for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) | ||
312 | if (phy->id == (phy_hwid >> 4) || phy->id == 0) | ||
313 | break; | ||
314 | |||
315 | if (i >= ARRAY_SIZE(phy_info)) { | ||
316 | printk(KERN_ERR DRV_MODULE_NAME | ||
317 | ": %s PHY id 0x%08x is not supported!\n", | ||
318 | dev->name, phy_hwid); | ||
319 | return -1; | ||
320 | } | ||
321 | |||
322 | fep->phy = phy; | ||
323 | |||
324 | printk(KERN_INFO DRV_MODULE_NAME | ||
325 | ": %s Phy @ 0x%x, type %s (0x%08x)\n", | ||
326 | dev->name, phy_id, fep->phy->name, phy_hwid); | ||
327 | |||
328 | return phy_id; | ||
329 | } | ||
330 | |||
331 | void fec_mii_startup(struct net_device *dev) | ||
332 | { | ||
333 | struct fec_enet_private *fep = netdev_priv(dev); | ||
334 | const struct fec_platform_info *fpi = fep->fpi; | ||
335 | |||
336 | if (!fpi->use_mdio || fep->phy == NULL) | ||
337 | return; | ||
338 | |||
339 | if (fep->phy->startup == NULL) | ||
340 | return; | ||
341 | |||
342 | (*fep->phy->startup) (dev); | ||
343 | } | ||
344 | |||
345 | void fec_mii_shutdown(struct net_device *dev) | ||
346 | { | ||
347 | struct fec_enet_private *fep = netdev_priv(dev); | ||
348 | const struct fec_platform_info *fpi = fep->fpi; | ||
349 | |||
350 | if (!fpi->use_mdio || fep->phy == NULL) | ||
351 | return; | ||
352 | |||
353 | if (fep->phy->shutdown == NULL) | ||
354 | return; | ||
355 | |||
356 | (*fep->phy->shutdown) (dev); | ||
357 | } | ||
358 | |||
359 | void fec_mii_ack_int(struct net_device *dev) | ||
360 | { | ||
361 | struct fec_enet_private *fep = netdev_priv(dev); | ||
362 | const struct fec_platform_info *fpi = fep->fpi; | ||
363 | |||
364 | if (!fpi->use_mdio || fep->phy == NULL) | ||
365 | return; | ||
366 | |||
367 | if (fep->phy->ack_int == NULL) | ||
368 | return; | ||
369 | |||
370 | (*fep->phy->ack_int) (dev); | ||
371 | } | ||
372 | |||
373 | /* helper function */ | ||
374 | static int mii_negotiated(struct mii_if_info *mii) | ||
375 | { | ||
376 | int advert, lpa, val; | ||
377 | |||
378 | if (!mii_link_ok(mii)) | ||
379 | return 0; | ||
380 | |||
381 | val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR); | ||
382 | if ((val & BMSR_ANEGCOMPLETE) == 0) | ||
383 | return 0; | ||
384 | |||
385 | advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE); | ||
386 | lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA); | ||
387 | |||
388 | return mii_nway_result(advert & lpa); | ||
389 | } | ||
390 | |||
391 | void fec_mii_link_status_change_check(struct net_device *dev, int init_media) | ||
392 | { | ||
393 | struct fec_enet_private *fep = netdev_priv(dev); | ||
394 | unsigned int media; | ||
395 | unsigned long flags; | ||
396 | |||
397 | if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0) | ||
398 | return; | ||
399 | |||
400 | media = mii_negotiated(&fep->mii_if); | ||
401 | |||
402 | if (netif_carrier_ok(dev)) { | ||
403 | spin_lock_irqsave(&fep->lock, flags); | ||
404 | fec_restart(dev, !!(media & ADVERTISE_FULL), | ||
405 | (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ? | ||
406 | 100 : 10); | ||
407 | spin_unlock_irqrestore(&fep->lock, flags); | ||
408 | |||
409 | netif_start_queue(dev); | ||
410 | } else { | ||
411 | netif_stop_queue(dev); | ||
412 | |||
413 | spin_lock_irqsave(&fep->lock, flags); | ||
414 | fec_stop(dev); | ||
415 | spin_unlock_irqrestore(&fep->lock, flags); | ||
416 | |||
417 | } | ||
418 | } | ||