diff options
author | Bryan Wu <bryan.wu@canonical.com> | 2010-03-30 22:10:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-01 22:53:13 -0400 |
commit | e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8 (patch) | |
tree | df7adaf0e220436ba0b5b5219e930a1b6697e4b3 /drivers/net/fec.c | |
parent | 5acbbd428db47b12f137a8a2aa96b3c0a96b744e (diff) |
netdev/fec.c: add phylib supporting to enable carrier detection (v2)
BugLink: http://bugs.launchpad.net/bugs/457878
v2:
- remove duplicated phy_speed caculation
- fix the phy_speed caculation according to the DataSheet
v1:
- removed old MII phy control code
- add phylib supporting
- add ethtool interface to make user space NetworkManager works
Tested on Freescale i.MX51 Babbage board.
This patch is based on a patch from Frederic Rodo <fred.rodo@gmail.com>
Cc: Frederic Rodo <fred.rodo@gmail.com>
Signed-off-by: Bryan Wu <bryan.wu@canonical.com>
Acked-by: Amit Kucheria <amit.kucheria@canonical.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fec.c')
-rw-r--r-- | drivers/net/fec.c | 1128 |
1 files changed, 251 insertions, 877 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 9f98c1c4a344..848eb1968abf 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/irq.h> | 40 | #include <linux/irq.h> |
41 | #include <linux/clk.h> | 41 | #include <linux/clk.h> |
42 | #include <linux/platform_device.h> | 42 | #include <linux/platform_device.h> |
43 | #include <linux/phy.h> | ||
43 | 44 | ||
44 | #include <asm/cacheflush.h> | 45 | #include <asm/cacheflush.h> |
45 | 46 | ||
@@ -61,7 +62,6 @@ | |||
61 | * Define the fixed address of the FEC hardware. | 62 | * Define the fixed address of the FEC hardware. |
62 | */ | 63 | */ |
63 | #if defined(CONFIG_M5272) | 64 | #if defined(CONFIG_M5272) |
64 | #define HAVE_mii_link_interrupt | ||
65 | 65 | ||
66 | static unsigned char fec_mac_default[] = { | 66 | static unsigned char fec_mac_default[] = { |
67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
@@ -86,23 +86,6 @@ static unsigned char fec_mac_default[] = { | |||
86 | #endif | 86 | #endif |
87 | #endif /* CONFIG_M5272 */ | 87 | #endif /* CONFIG_M5272 */ |
88 | 88 | ||
89 | /* Forward declarations of some structures to support different PHYs */ | ||
90 | |||
91 | typedef struct { | ||
92 | uint mii_data; | ||
93 | void (*funct)(uint mii_reg, struct net_device *dev); | ||
94 | } phy_cmd_t; | ||
95 | |||
96 | typedef struct { | ||
97 | uint id; | ||
98 | char *name; | ||
99 | |||
100 | const phy_cmd_t *config; | ||
101 | const phy_cmd_t *startup; | ||
102 | const phy_cmd_t *ack_int; | ||
103 | const phy_cmd_t *shutdown; | ||
104 | } phy_info_t; | ||
105 | |||
106 | /* The number of Tx and Rx buffers. These are allocated from the page | 89 | /* The number of Tx and Rx buffers. These are allocated from the page |
107 | * pool. The code may assume these are power of two, so it it best | 90 | * pool. The code may assume these are power of two, so it it best |
108 | * to keep them that size. | 91 | * to keep them that size. |
@@ -189,29 +172,21 @@ struct fec_enet_private { | |||
189 | uint tx_full; | 172 | uint tx_full; |
190 | /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ | 173 | /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ |
191 | spinlock_t hw_lock; | 174 | spinlock_t hw_lock; |
192 | /* hold while accessing the mii_list_t() elements */ | ||
193 | spinlock_t mii_lock; | ||
194 | |||
195 | uint phy_id; | ||
196 | uint phy_id_done; | ||
197 | uint phy_status; | ||
198 | uint phy_speed; | ||
199 | phy_info_t const *phy; | ||
200 | struct work_struct phy_task; | ||
201 | 175 | ||
202 | uint sequence_done; | 176 | struct platform_device *pdev; |
203 | uint mii_phy_task_queued; | ||
204 | 177 | ||
205 | uint phy_addr; | 178 | int opened; |
206 | 179 | ||
180 | /* Phylib and MDIO interface */ | ||
181 | struct mii_bus *mii_bus; | ||
182 | struct phy_device *phy_dev; | ||
183 | int mii_timeout; | ||
184 | uint phy_speed; | ||
207 | int index; | 185 | int index; |
208 | int opened; | ||
209 | int link; | 186 | int link; |
210 | int old_link; | ||
211 | int full_duplex; | 187 | int full_duplex; |
212 | }; | 188 | }; |
213 | 189 | ||
214 | static void fec_enet_mii(struct net_device *dev); | ||
215 | static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); | 190 | static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); |
216 | static void fec_enet_tx(struct net_device *dev); | 191 | static void fec_enet_tx(struct net_device *dev); |
217 | static void fec_enet_rx(struct net_device *dev); | 192 | static void fec_enet_rx(struct net_device *dev); |
@@ -219,67 +194,20 @@ static int fec_enet_close(struct net_device *dev); | |||
219 | static void fec_restart(struct net_device *dev, int duplex); | 194 | static void fec_restart(struct net_device *dev, int duplex); |
220 | static void fec_stop(struct net_device *dev); | 195 | static void fec_stop(struct net_device *dev); |
221 | 196 | ||
197 | /* FEC MII MMFR bits definition */ | ||
198 | #define FEC_MMFR_ST (1 << 30) | ||
199 | #define FEC_MMFR_OP_READ (2 << 28) | ||
200 | #define FEC_MMFR_OP_WRITE (1 << 28) | ||
201 | #define FEC_MMFR_PA(v) ((v & 0x1f) << 23) | ||
202 | #define FEC_MMFR_RA(v) ((v & 0x1f) << 18) | ||
203 | #define FEC_MMFR_TA (2 << 16) | ||
204 | #define FEC_MMFR_DATA(v) (v & 0xffff) | ||
222 | 205 | ||
223 | /* MII processing. We keep this as simple as possible. Requests are | 206 | #define FEC_MII_TIMEOUT 10000 |
224 | * placed on the list (if there is room). When the request is finished | ||
225 | * by the MII, an optional function may be called. | ||
226 | */ | ||
227 | typedef struct mii_list { | ||
228 | uint mii_regval; | ||
229 | void (*mii_func)(uint val, struct net_device *dev); | ||
230 | struct mii_list *mii_next; | ||
231 | } mii_list_t; | ||
232 | |||
233 | #define NMII 20 | ||
234 | static mii_list_t mii_cmds[NMII]; | ||
235 | static mii_list_t *mii_free; | ||
236 | static mii_list_t *mii_head; | ||
237 | static mii_list_t *mii_tail; | ||
238 | |||
239 | static int mii_queue(struct net_device *dev, int request, | ||
240 | void (*func)(uint, struct net_device *)); | ||
241 | |||
242 | /* Make MII read/write commands for the FEC */ | ||
243 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
244 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ | ||
245 | (VAL & 0xffff)) | ||
246 | #define mk_mii_end 0 | ||
247 | 207 | ||
248 | /* Transmitter timeout */ | 208 | /* Transmitter timeout */ |
249 | #define TX_TIMEOUT (2 * HZ) | 209 | #define TX_TIMEOUT (2 * HZ) |
250 | 210 | ||
251 | /* Register definitions for the PHY */ | ||
252 | |||
253 | #define MII_REG_CR 0 /* Control Register */ | ||
254 | #define MII_REG_SR 1 /* Status Register */ | ||
255 | #define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ | ||
256 | #define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ | ||
257 | #define MII_REG_ANAR 4 /* A-N Advertisement Register */ | ||
258 | #define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ | ||
259 | #define MII_REG_ANER 6 /* A-N Expansion Register */ | ||
260 | #define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ | ||
261 | #define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */ | ||
262 | |||
263 | /* values for phy_status */ | ||
264 | |||
265 | #define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ | ||
266 | #define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ | ||
267 | #define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ | ||
268 | #define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ | ||
269 | #define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ | ||
270 | #define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ | ||
271 | #define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ | ||
272 | |||
273 | #define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ | ||
274 | #define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ | ||
275 | #define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ | ||
276 | #define PHY_STAT_SPMASK 0xf000 /* mask for speed */ | ||
277 | #define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ | ||
278 | #define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ | ||
279 | #define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ | ||
280 | #define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ | ||
281 | |||
282 | |||
283 | static int | 211 | static int |
284 | fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | 212 | fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) |
285 | { | 213 | { |
@@ -406,12 +334,6 @@ fec_enet_interrupt(int irq, void * dev_id) | |||
406 | ret = IRQ_HANDLED; | 334 | ret = IRQ_HANDLED; |
407 | fec_enet_tx(dev); | 335 | fec_enet_tx(dev); |
408 | } | 336 | } |
409 | |||
410 | if (int_events & FEC_ENET_MII) { | ||
411 | ret = IRQ_HANDLED; | ||
412 | fec_enet_mii(dev); | ||
413 | } | ||
414 | |||
415 | } while (int_events); | 337 | } while (int_events); |
416 | 338 | ||
417 | return ret; | 339 | return ret; |
@@ -607,827 +529,311 @@ rx_processing_done: | |||
607 | spin_unlock(&fep->hw_lock); | 529 | spin_unlock(&fep->hw_lock); |
608 | } | 530 | } |
609 | 531 | ||
610 | /* called from interrupt context */ | 532 | /* ------------------------------------------------------------------------- */ |
611 | static void | 533 | #ifdef CONFIG_M5272 |
612 | fec_enet_mii(struct net_device *dev) | 534 | static void __inline__ fec_get_mac(struct net_device *dev) |
613 | { | ||
614 | struct fec_enet_private *fep; | ||
615 | mii_list_t *mip; | ||
616 | |||
617 | fep = netdev_priv(dev); | ||
618 | spin_lock(&fep->mii_lock); | ||
619 | |||
620 | if ((mip = mii_head) == NULL) { | ||
621 | printk("MII and no head!\n"); | ||
622 | goto unlock; | ||
623 | } | ||
624 | |||
625 | if (mip->mii_func != NULL) | ||
626 | (*(mip->mii_func))(readl(fep->hwp + FEC_MII_DATA), dev); | ||
627 | |||
628 | mii_head = mip->mii_next; | ||
629 | mip->mii_next = mii_free; | ||
630 | mii_free = mip; | ||
631 | |||
632 | if ((mip = mii_head) != NULL) | ||
633 | writel(mip->mii_regval, fep->hwp + FEC_MII_DATA); | ||
634 | |||
635 | unlock: | ||
636 | spin_unlock(&fep->mii_lock); | ||
637 | } | ||
638 | |||
639 | static int | ||
640 | mii_queue_unlocked(struct net_device *dev, int regval, | ||
641 | void (*func)(uint, struct net_device *)) | ||
642 | { | 535 | { |
643 | struct fec_enet_private *fep; | 536 | struct fec_enet_private *fep = netdev_priv(dev); |
644 | mii_list_t *mip; | 537 | unsigned char *iap, tmpaddr[ETH_ALEN]; |
645 | int retval; | ||
646 | |||
647 | /* Add PHY address to register command */ | ||
648 | fep = netdev_priv(dev); | ||
649 | 538 | ||
650 | regval |= fep->phy_addr << 23; | 539 | if (FEC_FLASHMAC) { |
651 | retval = 0; | 540 | /* |
652 | 541 | * Get MAC address from FLASH. | |
653 | if ((mip = mii_free) != NULL) { | 542 | * If it is all 1's or 0's, use the default. |
654 | mii_free = mip->mii_next; | 543 | */ |
655 | mip->mii_regval = regval; | 544 | iap = (unsigned char *)FEC_FLASHMAC; |
656 | mip->mii_func = func; | 545 | if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && |
657 | mip->mii_next = NULL; | 546 | (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) |
658 | if (mii_head) { | 547 | iap = fec_mac_default; |
659 | mii_tail->mii_next = mip; | 548 | if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && |
660 | mii_tail = mip; | 549 | (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) |
661 | } else { | 550 | iap = fec_mac_default; |
662 | mii_head = mii_tail = mip; | ||
663 | writel(regval, fep->hwp + FEC_MII_DATA); | ||
664 | } | ||
665 | } else { | 551 | } else { |
666 | retval = 1; | 552 | *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW); |
553 | *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16); | ||
554 | iap = &tmpaddr[0]; | ||
667 | } | 555 | } |
668 | 556 | ||
669 | return retval; | 557 | memcpy(dev->dev_addr, iap, ETH_ALEN); |
670 | } | ||
671 | |||
672 | static int | ||
673 | mii_queue(struct net_device *dev, int regval, | ||
674 | void (*func)(uint, struct net_device *)) | ||
675 | { | ||
676 | struct fec_enet_private *fep; | ||
677 | unsigned long flags; | ||
678 | int retval; | ||
679 | fep = netdev_priv(dev); | ||
680 | spin_lock_irqsave(&fep->mii_lock, flags); | ||
681 | retval = mii_queue_unlocked(dev, regval, func); | ||
682 | spin_unlock_irqrestore(&fep->mii_lock, flags); | ||
683 | return retval; | ||
684 | } | ||
685 | |||
686 | static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) | ||
687 | { | ||
688 | if(!c) | ||
689 | return; | ||
690 | 558 | ||
691 | for (; c->mii_data != mk_mii_end; c++) | 559 | /* Adjust MAC if using default MAC address */ |
692 | mii_queue(dev, c->mii_data, c->funct); | 560 | if (iap == fec_mac_default) |
561 | dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; | ||
693 | } | 562 | } |
563 | #endif | ||
694 | 564 | ||
695 | static void mii_parse_sr(uint mii_reg, struct net_device *dev) | 565 | /* ------------------------------------------------------------------------- */ |
696 | { | ||
697 | struct fec_enet_private *fep = netdev_priv(dev); | ||
698 | volatile uint *s = &(fep->phy_status); | ||
699 | uint status; | ||
700 | |||
701 | status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); | ||
702 | |||
703 | if (mii_reg & 0x0004) | ||
704 | status |= PHY_STAT_LINK; | ||
705 | if (mii_reg & 0x0010) | ||
706 | status |= PHY_STAT_FAULT; | ||
707 | if (mii_reg & 0x0020) | ||
708 | status |= PHY_STAT_ANC; | ||
709 | *s = status; | ||
710 | } | ||
711 | 566 | ||
712 | static void mii_parse_cr(uint mii_reg, struct net_device *dev) | 567 | /* |
568 | * Phy section | ||
569 | */ | ||
570 | static void fec_enet_adjust_link(struct net_device *dev) | ||
713 | { | 571 | { |
714 | struct fec_enet_private *fep = netdev_priv(dev); | 572 | struct fec_enet_private *fep = netdev_priv(dev); |
715 | volatile uint *s = &(fep->phy_status); | 573 | struct phy_device *phy_dev = fep->phy_dev; |
716 | uint status; | 574 | unsigned long flags; |
717 | |||
718 | status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP); | ||
719 | |||
720 | if (mii_reg & 0x1000) | ||
721 | status |= PHY_CONF_ANE; | ||
722 | if (mii_reg & 0x4000) | ||
723 | status |= PHY_CONF_LOOP; | ||
724 | *s = status; | ||
725 | } | ||
726 | 575 | ||
727 | static void mii_parse_anar(uint mii_reg, struct net_device *dev) | 576 | int status_change = 0; |
728 | { | ||
729 | struct fec_enet_private *fep = netdev_priv(dev); | ||
730 | volatile uint *s = &(fep->phy_status); | ||
731 | uint status; | ||
732 | |||
733 | status = *s & ~(PHY_CONF_SPMASK); | ||
734 | |||
735 | if (mii_reg & 0x0020) | ||
736 | status |= PHY_CONF_10HDX; | ||
737 | if (mii_reg & 0x0040) | ||
738 | status |= PHY_CONF_10FDX; | ||
739 | if (mii_reg & 0x0080) | ||
740 | status |= PHY_CONF_100HDX; | ||
741 | if (mii_reg & 0x00100) | ||
742 | status |= PHY_CONF_100FDX; | ||
743 | *s = status; | ||
744 | } | ||
745 | 577 | ||
746 | /* ------------------------------------------------------------------------- */ | 578 | spin_lock_irqsave(&fep->hw_lock, flags); |
747 | /* The Level one LXT970 is used by many boards */ | ||
748 | 579 | ||
749 | #define MII_LXT970_MIRROR 16 /* Mirror register */ | 580 | /* Prevent a state halted on mii error */ |
750 | #define MII_LXT970_IER 17 /* Interrupt Enable Register */ | 581 | if (fep->mii_timeout && phy_dev->state == PHY_HALTED) { |
751 | #define MII_LXT970_ISR 18 /* Interrupt Status Register */ | 582 | phy_dev->state = PHY_RESUMING; |
752 | #define MII_LXT970_CONFIG 19 /* Configuration Register */ | 583 | goto spin_unlock; |
753 | #define MII_LXT970_CSR 20 /* Chip Status Register */ | 584 | } |
754 | 585 | ||
755 | static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) | 586 | /* Duplex link change */ |
756 | { | 587 | if (phy_dev->link) { |
757 | struct fec_enet_private *fep = netdev_priv(dev); | 588 | if (fep->full_duplex != phy_dev->duplex) { |
758 | volatile uint *s = &(fep->phy_status); | 589 | fec_restart(dev, phy_dev->duplex); |
759 | uint status; | 590 | status_change = 1; |
591 | } | ||
592 | } | ||
760 | 593 | ||
761 | status = *s & ~(PHY_STAT_SPMASK); | 594 | /* Link on or off change */ |
762 | if (mii_reg & 0x0800) { | 595 | if (phy_dev->link != fep->link) { |
763 | if (mii_reg & 0x1000) | 596 | fep->link = phy_dev->link; |
764 | status |= PHY_STAT_100FDX; | 597 | if (phy_dev->link) |
598 | fec_restart(dev, phy_dev->duplex); | ||
765 | else | 599 | else |
766 | status |= PHY_STAT_100HDX; | 600 | fec_stop(dev); |
767 | } else { | 601 | status_change = 1; |
768 | if (mii_reg & 0x1000) | ||
769 | status |= PHY_STAT_10FDX; | ||
770 | else | ||
771 | status |= PHY_STAT_10HDX; | ||
772 | } | 602 | } |
773 | *s = status; | ||
774 | } | ||
775 | |||
776 | static phy_cmd_t const phy_cmd_lxt970_config[] = { | ||
777 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
778 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
779 | { mk_mii_end, } | ||
780 | }; | ||
781 | static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */ | ||
782 | { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, | ||
783 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
784 | { mk_mii_end, } | ||
785 | }; | ||
786 | static phy_cmd_t const phy_cmd_lxt970_ack_int[] = { | ||
787 | /* read SR and ISR to acknowledge */ | ||
788 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
789 | { mk_mii_read(MII_LXT970_ISR), NULL }, | ||
790 | |||
791 | /* find out the current status */ | ||
792 | { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, | ||
793 | { mk_mii_end, } | ||
794 | }; | ||
795 | static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */ | ||
796 | { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, | ||
797 | { mk_mii_end, } | ||
798 | }; | ||
799 | static phy_info_t const phy_info_lxt970 = { | ||
800 | .id = 0x07810000, | ||
801 | .name = "LXT970", | ||
802 | .config = phy_cmd_lxt970_config, | ||
803 | .startup = phy_cmd_lxt970_startup, | ||
804 | .ack_int = phy_cmd_lxt970_ack_int, | ||
805 | .shutdown = phy_cmd_lxt970_shutdown | ||
806 | }; | ||
807 | 603 | ||
808 | /* ------------------------------------------------------------------------- */ | 604 | spin_unlock: |
809 | /* The Level one LXT971 is used on some of my custom boards */ | 605 | spin_unlock_irqrestore(&fep->hw_lock, flags); |
810 | |||
811 | /* register definitions for the 971 */ | ||
812 | 606 | ||
813 | #define MII_LXT971_PCR 16 /* Port Control Register */ | 607 | if (status_change) |
814 | #define MII_LXT971_SR2 17 /* Status Register 2 */ | 608 | phy_print_status(phy_dev); |
815 | #define MII_LXT971_IER 18 /* Interrupt Enable Register */ | 609 | } |
816 | #define MII_LXT971_ISR 19 /* Interrupt Status Register */ | ||
817 | #define MII_LXT971_LCR 20 /* LED Control Register */ | ||
818 | #define MII_LXT971_TCR 30 /* Transmit Control Register */ | ||
819 | 610 | ||
820 | /* | 611 | /* |
821 | * I had some nice ideas of running the MDIO faster... | 612 | * NOTE: a MII transaction is during around 25 us, so polling it... |
822 | * The 971 should support 8MHz and I tried it, but things acted really | ||
823 | * weird, so 2.5 MHz ought to be enough for anyone... | ||
824 | */ | 613 | */ |
825 | 614 | static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | |
826 | static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) | ||
827 | { | 615 | { |
828 | struct fec_enet_private *fep = netdev_priv(dev); | 616 | struct fec_enet_private *fep = bus->priv; |
829 | volatile uint *s = &(fep->phy_status); | 617 | int timeout = FEC_MII_TIMEOUT; |
830 | uint status; | ||
831 | 618 | ||
832 | status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); | 619 | fep->mii_timeout = 0; |
833 | 620 | ||
834 | if (mii_reg & 0x0400) { | 621 | /* clear MII end of transfer bit*/ |
835 | fep->link = 1; | 622 | writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); |
836 | status |= PHY_STAT_LINK; | 623 | |
837 | } else { | 624 | /* start a read op */ |
838 | fep->link = 0; | 625 | writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | |
839 | } | 626 | FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | |
840 | if (mii_reg & 0x0080) | 627 | FEC_MMFR_TA, fep->hwp + FEC_MII_DATA); |
841 | status |= PHY_STAT_ANC; | 628 | |
842 | if (mii_reg & 0x4000) { | 629 | /* wait for end of transfer */ |
843 | if (mii_reg & 0x0200) | 630 | while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) { |
844 | status |= PHY_STAT_100FDX; | 631 | cpu_relax(); |
845 | else | 632 | if (timeout-- < 0) { |
846 | status |= PHY_STAT_100HDX; | 633 | fep->mii_timeout = 1; |
847 | } else { | 634 | printk(KERN_ERR "FEC: MDIO read timeout\n"); |
848 | if (mii_reg & 0x0200) | 635 | return -ETIMEDOUT; |
849 | status |= PHY_STAT_10FDX; | 636 | } |
850 | else | ||
851 | status |= PHY_STAT_10HDX; | ||
852 | } | 637 | } |
853 | if (mii_reg & 0x0008) | ||
854 | status |= PHY_STAT_FAULT; | ||
855 | 638 | ||
856 | *s = status; | 639 | /* return value */ |
640 | return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); | ||
857 | } | 641 | } |
858 | 642 | ||
859 | static phy_cmd_t const phy_cmd_lxt971_config[] = { | 643 | static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, |
860 | /* limit to 10MBit because my prototype board | 644 | u16 value) |
861 | * doesn't work with 100. */ | ||
862 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
863 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
864 | { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, | ||
865 | { mk_mii_end, } | ||
866 | }; | ||
867 | static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */ | ||
868 | { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, | ||
869 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
870 | { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */ | ||
871 | /* Somehow does the 971 tell me that the link is down | ||
872 | * the first read after power-up. | ||
873 | * read here to get a valid value in ack_int */ | ||
874 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
875 | { mk_mii_end, } | ||
876 | }; | ||
877 | static phy_cmd_t const phy_cmd_lxt971_ack_int[] = { | ||
878 | /* acknowledge the int before reading status ! */ | ||
879 | { mk_mii_read(MII_LXT971_ISR), NULL }, | ||
880 | /* find out the current status */ | ||
881 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
882 | { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, | ||
883 | { mk_mii_end, } | ||
884 | }; | ||
885 | static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */ | ||
886 | { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, | ||
887 | { mk_mii_end, } | ||
888 | }; | ||
889 | static phy_info_t const phy_info_lxt971 = { | ||
890 | .id = 0x0001378e, | ||
891 | .name = "LXT971", | ||
892 | .config = phy_cmd_lxt971_config, | ||
893 | .startup = phy_cmd_lxt971_startup, | ||
894 | .ack_int = phy_cmd_lxt971_ack_int, | ||
895 | .shutdown = phy_cmd_lxt971_shutdown | ||
896 | }; | ||
897 | |||
898 | /* ------------------------------------------------------------------------- */ | ||
899 | /* The Quality Semiconductor QS6612 is used on the RPX CLLF */ | ||
900 | |||
901 | /* register definitions */ | ||
902 | |||
903 | #define MII_QS6612_MCR 17 /* Mode Control Register */ | ||
904 | #define MII_QS6612_FTR 27 /* Factory Test Register */ | ||
905 | #define MII_QS6612_MCO 28 /* Misc. Control Register */ | ||
906 | #define MII_QS6612_ISR 29 /* Interrupt Source Register */ | ||
907 | #define MII_QS6612_IMR 30 /* Interrupt Mask Register */ | ||
908 | #define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ | ||
909 | |||
910 | static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) | ||
911 | { | 645 | { |
912 | struct fec_enet_private *fep = netdev_priv(dev); | 646 | struct fec_enet_private *fep = bus->priv; |
913 | volatile uint *s = &(fep->phy_status); | 647 | int timeout = FEC_MII_TIMEOUT; |
914 | uint status; | ||
915 | 648 | ||
916 | status = *s & ~(PHY_STAT_SPMASK); | 649 | fep->mii_timeout = 0; |
917 | 650 | ||
918 | switch((mii_reg >> 2) & 7) { | 651 | /* clear MII end of transfer bit*/ |
919 | case 1: status |= PHY_STAT_10HDX; break; | 652 | writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); |
920 | case 2: status |= PHY_STAT_100HDX; break; | ||
921 | case 5: status |= PHY_STAT_10FDX; break; | ||
922 | case 6: status |= PHY_STAT_100FDX; break; | ||
923 | } | ||
924 | |||
925 | *s = status; | ||
926 | } | ||
927 | |||
928 | static phy_cmd_t const phy_cmd_qs6612_config[] = { | ||
929 | /* The PHY powers up isolated on the RPX, | ||
930 | * so send a command to allow operation. | ||
931 | */ | ||
932 | { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, | ||
933 | |||
934 | /* parse cr and anar to get some info */ | ||
935 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
936 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
937 | { mk_mii_end, } | ||
938 | }; | ||
939 | static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */ | ||
940 | { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, | ||
941 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
942 | { mk_mii_end, } | ||
943 | }; | ||
944 | static phy_cmd_t const phy_cmd_qs6612_ack_int[] = { | ||
945 | /* we need to read ISR, SR and ANER to acknowledge */ | ||
946 | { mk_mii_read(MII_QS6612_ISR), NULL }, | ||
947 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
948 | { mk_mii_read(MII_REG_ANER), NULL }, | ||
949 | |||
950 | /* read pcr to get info */ | ||
951 | { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, | ||
952 | { mk_mii_end, } | ||
953 | }; | ||
954 | static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */ | ||
955 | { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, | ||
956 | { mk_mii_end, } | ||
957 | }; | ||
958 | static phy_info_t const phy_info_qs6612 = { | ||
959 | .id = 0x00181440, | ||
960 | .name = "QS6612", | ||
961 | .config = phy_cmd_qs6612_config, | ||
962 | .startup = phy_cmd_qs6612_startup, | ||
963 | .ack_int = phy_cmd_qs6612_ack_int, | ||
964 | .shutdown = phy_cmd_qs6612_shutdown | ||
965 | }; | ||
966 | |||
967 | /* ------------------------------------------------------------------------- */ | ||
968 | /* AMD AM79C874 phy */ | ||
969 | 653 | ||
970 | /* register definitions for the 874 */ | 654 | /* start a read op */ |
655 | writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | | ||
656 | FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | | ||
657 | FEC_MMFR_TA | FEC_MMFR_DATA(value), | ||
658 | fep->hwp + FEC_MII_DATA); | ||
659 | |||
660 | /* wait for end of transfer */ | ||
661 | while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) { | ||
662 | cpu_relax(); | ||
663 | if (timeout-- < 0) { | ||
664 | fep->mii_timeout = 1; | ||
665 | printk(KERN_ERR "FEC: MDIO write timeout\n"); | ||
666 | return -ETIMEDOUT; | ||
667 | } | ||
668 | } | ||
971 | 669 | ||
972 | #define MII_AM79C874_MFR 16 /* Miscellaneous Feature Register */ | 670 | return 0; |
973 | #define MII_AM79C874_ICSR 17 /* Interrupt/Status Register */ | 671 | } |
974 | #define MII_AM79C874_DR 18 /* Diagnostic Register */ | ||
975 | #define MII_AM79C874_PMLR 19 /* Power and Loopback Register */ | ||
976 | #define MII_AM79C874_MCR 21 /* ModeControl Register */ | ||
977 | #define MII_AM79C874_DC 23 /* Disconnect Counter */ | ||
978 | #define MII_AM79C874_REC 24 /* Recieve Error Counter */ | ||
979 | 672 | ||
980 | static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) | 673 | static int fec_enet_mdio_reset(struct mii_bus *bus) |
981 | { | 674 | { |
982 | struct fec_enet_private *fep = netdev_priv(dev); | 675 | return 0; |
983 | volatile uint *s = &(fep->phy_status); | ||
984 | uint status; | ||
985 | |||
986 | status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC); | ||
987 | |||
988 | if (mii_reg & 0x0080) | ||
989 | status |= PHY_STAT_ANC; | ||
990 | if (mii_reg & 0x0400) | ||
991 | status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); | ||
992 | else | ||
993 | status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); | ||
994 | |||
995 | *s = status; | ||
996 | } | 676 | } |
997 | 677 | ||
998 | static phy_cmd_t const phy_cmd_am79c874_config[] = { | 678 | static int fec_enet_mii_probe(struct net_device *dev) |
999 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
1000 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
1001 | { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, | ||
1002 | { mk_mii_end, } | ||
1003 | }; | ||
1004 | static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */ | ||
1005 | { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL }, | ||
1006 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
1007 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1008 | { mk_mii_end, } | ||
1009 | }; | ||
1010 | static phy_cmd_t const phy_cmd_am79c874_ack_int[] = { | ||
1011 | /* find out the current status */ | ||
1012 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1013 | { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, | ||
1014 | /* we only need to read ISR to acknowledge */ | ||
1015 | { mk_mii_read(MII_AM79C874_ICSR), NULL }, | ||
1016 | { mk_mii_end, } | ||
1017 | }; | ||
1018 | static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */ | ||
1019 | { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL }, | ||
1020 | { mk_mii_end, } | ||
1021 | }; | ||
1022 | static phy_info_t const phy_info_am79c874 = { | ||
1023 | .id = 0x00022561, | ||
1024 | .name = "AM79C874", | ||
1025 | .config = phy_cmd_am79c874_config, | ||
1026 | .startup = phy_cmd_am79c874_startup, | ||
1027 | .ack_int = phy_cmd_am79c874_ack_int, | ||
1028 | .shutdown = phy_cmd_am79c874_shutdown | ||
1029 | }; | ||
1030 | |||
1031 | |||
1032 | /* ------------------------------------------------------------------------- */ | ||
1033 | /* Kendin KS8721BL phy */ | ||
1034 | |||
1035 | /* register definitions for the 8721 */ | ||
1036 | |||
1037 | #define MII_KS8721BL_RXERCR 21 | ||
1038 | #define MII_KS8721BL_ICSR 27 | ||
1039 | #define MII_KS8721BL_PHYCR 31 | ||
1040 | |||
1041 | static phy_cmd_t const phy_cmd_ks8721bl_config[] = { | ||
1042 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
1043 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
1044 | { mk_mii_end, } | ||
1045 | }; | ||
1046 | static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */ | ||
1047 | { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL }, | ||
1048 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
1049 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1050 | { mk_mii_end, } | ||
1051 | }; | ||
1052 | static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = { | ||
1053 | /* find out the current status */ | ||
1054 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1055 | /* we only need to read ISR to acknowledge */ | ||
1056 | { mk_mii_read(MII_KS8721BL_ICSR), NULL }, | ||
1057 | { mk_mii_end, } | ||
1058 | }; | ||
1059 | static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */ | ||
1060 | { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL }, | ||
1061 | { mk_mii_end, } | ||
1062 | }; | ||
1063 | static phy_info_t const phy_info_ks8721bl = { | ||
1064 | .id = 0x00022161, | ||
1065 | .name = "KS8721BL", | ||
1066 | .config = phy_cmd_ks8721bl_config, | ||
1067 | .startup = phy_cmd_ks8721bl_startup, | ||
1068 | .ack_int = phy_cmd_ks8721bl_ack_int, | ||
1069 | .shutdown = phy_cmd_ks8721bl_shutdown | ||
1070 | }; | ||
1071 | |||
1072 | /* ------------------------------------------------------------------------- */ | ||
1073 | /* register definitions for the DP83848 */ | ||
1074 | |||
1075 | #define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ | ||
1076 | |||
1077 | static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) | ||
1078 | { | 679 | { |
1079 | struct fec_enet_private *fep = netdev_priv(dev); | 680 | struct fec_enet_private *fep = netdev_priv(dev); |
1080 | volatile uint *s = &(fep->phy_status); | 681 | struct phy_device *phy_dev = NULL; |
1081 | 682 | int phy_addr; | |
1082 | *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); | ||
1083 | |||
1084 | /* Link up */ | ||
1085 | if (mii_reg & 0x0001) { | ||
1086 | fep->link = 1; | ||
1087 | *s |= PHY_STAT_LINK; | ||
1088 | } else | ||
1089 | fep->link = 0; | ||
1090 | /* Status of link */ | ||
1091 | if (mii_reg & 0x0010) /* Autonegotioation complete */ | ||
1092 | *s |= PHY_STAT_ANC; | ||
1093 | if (mii_reg & 0x0002) { /* 10MBps? */ | ||
1094 | if (mii_reg & 0x0004) /* Full Duplex? */ | ||
1095 | *s |= PHY_STAT_10FDX; | ||
1096 | else | ||
1097 | *s |= PHY_STAT_10HDX; | ||
1098 | } else { /* 100 Mbps? */ | ||
1099 | if (mii_reg & 0x0004) /* Full Duplex? */ | ||
1100 | *s |= PHY_STAT_100FDX; | ||
1101 | else | ||
1102 | *s |= PHY_STAT_100HDX; | ||
1103 | } | ||
1104 | if (mii_reg & 0x0008) | ||
1105 | *s |= PHY_STAT_FAULT; | ||
1106 | } | ||
1107 | |||
1108 | static phy_info_t phy_info_dp83848= { | ||
1109 | 0x020005c9, | ||
1110 | "DP83848", | ||
1111 | 683 | ||
1112 | (const phy_cmd_t []) { /* config */ | 684 | /* find the first phy */ |
1113 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | 685 | for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { |
1114 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | 686 | if (fep->mii_bus->phy_map[phy_addr]) { |
1115 | { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, | 687 | phy_dev = fep->mii_bus->phy_map[phy_addr]; |
1116 | { mk_mii_end, } | 688 | break; |
1117 | }, | 689 | } |
1118 | (const phy_cmd_t []) { /* startup - enable interrupts */ | 690 | } |
1119 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
1120 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1121 | { mk_mii_end, } | ||
1122 | }, | ||
1123 | (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ | ||
1124 | { mk_mii_end, } | ||
1125 | }, | ||
1126 | (const phy_cmd_t []) { /* shutdown */ | ||
1127 | { mk_mii_end, } | ||
1128 | }, | ||
1129 | }; | ||
1130 | 691 | ||
1131 | static phy_info_t phy_info_lan8700 = { | 692 | if (!phy_dev) { |
1132 | 0x0007C0C, | 693 | printk(KERN_ERR "%s: no PHY found\n", dev->name); |
1133 | "LAN8700", | 694 | return -ENODEV; |
1134 | (const phy_cmd_t []) { /* config */ | 695 | } |
1135 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
1136 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
1137 | { mk_mii_end, } | ||
1138 | }, | ||
1139 | (const phy_cmd_t []) { /* startup */ | ||
1140 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
1141 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1142 | { mk_mii_end, } | ||
1143 | }, | ||
1144 | (const phy_cmd_t []) { /* act_int */ | ||
1145 | { mk_mii_end, } | ||
1146 | }, | ||
1147 | (const phy_cmd_t []) { /* shutdown */ | ||
1148 | { mk_mii_end, } | ||
1149 | }, | ||
1150 | }; | ||
1151 | /* ------------------------------------------------------------------------- */ | ||
1152 | 696 | ||
1153 | static phy_info_t const * const phy_info[] = { | 697 | /* attach the mac to the phy */ |
1154 | &phy_info_lxt970, | 698 | phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), |
1155 | &phy_info_lxt971, | 699 | &fec_enet_adjust_link, 0, |
1156 | &phy_info_qs6612, | 700 | PHY_INTERFACE_MODE_MII); |
1157 | &phy_info_am79c874, | 701 | if (IS_ERR(phy_dev)) { |
1158 | &phy_info_ks8721bl, | 702 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); |
1159 | &phy_info_dp83848, | 703 | return PTR_ERR(phy_dev); |
1160 | &phy_info_lan8700, | 704 | } |
1161 | NULL | ||
1162 | }; | ||
1163 | 705 | ||
1164 | /* ------------------------------------------------------------------------- */ | 706 | /* mask with MAC supported features */ |
1165 | #ifdef HAVE_mii_link_interrupt | 707 | phy_dev->supported &= PHY_BASIC_FEATURES; |
1166 | static irqreturn_t | 708 | phy_dev->advertising = phy_dev->supported; |
1167 | mii_link_interrupt(int irq, void * dev_id); | ||
1168 | 709 | ||
1169 | /* | 710 | fep->phy_dev = phy_dev; |
1170 | * This is specific to the MII interrupt setup of the M5272EVB. | 711 | fep->link = 0; |
1171 | */ | 712 | fep->full_duplex = 0; |
1172 | static void __inline__ fec_request_mii_intr(struct net_device *dev) | ||
1173 | { | ||
1174 | if (request_irq(66, mii_link_interrupt, IRQF_DISABLED, "fec(MII)", dev) != 0) | ||
1175 | printk("FEC: Could not allocate fec(MII) IRQ(66)!\n"); | ||
1176 | } | ||
1177 | 713 | ||
1178 | static void __inline__ fec_disable_phy_intr(struct net_device *dev) | 714 | return 0; |
1179 | { | ||
1180 | free_irq(66, dev); | ||
1181 | } | 715 | } |
1182 | #endif | ||
1183 | 716 | ||
1184 | #ifdef CONFIG_M5272 | 717 | static int fec_enet_mii_init(struct platform_device *pdev) |
1185 | static void __inline__ fec_get_mac(struct net_device *dev) | ||
1186 | { | 718 | { |
719 | struct net_device *dev = platform_get_drvdata(pdev); | ||
1187 | struct fec_enet_private *fep = netdev_priv(dev); | 720 | struct fec_enet_private *fep = netdev_priv(dev); |
1188 | unsigned char *iap, tmpaddr[ETH_ALEN]; | 721 | int err = -ENXIO, i; |
1189 | 722 | ||
1190 | if (FEC_FLASHMAC) { | 723 | fep->mii_timeout = 0; |
1191 | /* | ||
1192 | * Get MAC address from FLASH. | ||
1193 | * If it is all 1's or 0's, use the default. | ||
1194 | */ | ||
1195 | iap = (unsigned char *)FEC_FLASHMAC; | ||
1196 | if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && | ||
1197 | (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) | ||
1198 | iap = fec_mac_default; | ||
1199 | if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && | ||
1200 | (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) | ||
1201 | iap = fec_mac_default; | ||
1202 | } else { | ||
1203 | *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW); | ||
1204 | *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16); | ||
1205 | iap = &tmpaddr[0]; | ||
1206 | } | ||
1207 | |||
1208 | memcpy(dev->dev_addr, iap, ETH_ALEN); | ||
1209 | |||
1210 | /* Adjust MAC if using default MAC address */ | ||
1211 | if (iap == fec_mac_default) | ||
1212 | dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; | ||
1213 | } | ||
1214 | #endif | ||
1215 | 724 | ||
1216 | /* ------------------------------------------------------------------------- */ | 725 | /* |
1217 | 726 | * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) | |
1218 | static void mii_display_status(struct net_device *dev) | 727 | */ |
1219 | { | 728 | fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; |
1220 | struct fec_enet_private *fep = netdev_priv(dev); | 729 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); |
1221 | volatile uint *s = &(fep->phy_status); | ||
1222 | 730 | ||
1223 | if (!fep->link && !fep->old_link) { | 731 | fep->mii_bus = mdiobus_alloc(); |
1224 | /* Link is still down - don't print anything */ | 732 | if (fep->mii_bus == NULL) { |
1225 | return; | 733 | err = -ENOMEM; |
734 | goto err_out; | ||
1226 | } | 735 | } |
1227 | 736 | ||
1228 | printk("%s: status: ", dev->name); | 737 | fep->mii_bus->name = "fec_enet_mii_bus"; |
1229 | 738 | fep->mii_bus->read = fec_enet_mdio_read; | |
1230 | if (!fep->link) { | 739 | fep->mii_bus->write = fec_enet_mdio_write; |
1231 | printk("link down"); | 740 | fep->mii_bus->reset = fec_enet_mdio_reset; |
1232 | } else { | 741 | snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); |
1233 | printk("link up"); | 742 | fep->mii_bus->priv = fep; |
1234 | 743 | fep->mii_bus->parent = &pdev->dev; | |
1235 | switch(*s & PHY_STAT_SPMASK) { | 744 | |
1236 | case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; | 745 | fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); |
1237 | case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; | 746 | if (!fep->mii_bus->irq) { |
1238 | case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; | 747 | err = -ENOMEM; |
1239 | case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; | 748 | goto err_out_free_mdiobus; |
1240 | default: | ||
1241 | printk(", Unknown speed/duplex"); | ||
1242 | } | ||
1243 | |||
1244 | if (*s & PHY_STAT_ANC) | ||
1245 | printk(", auto-negotiation complete"); | ||
1246 | } | 749 | } |
1247 | 750 | ||
1248 | if (*s & PHY_STAT_FAULT) | 751 | for (i = 0; i < PHY_MAX_ADDR; i++) |
1249 | printk(", remote fault"); | 752 | fep->mii_bus->irq[i] = PHY_POLL; |
1250 | |||
1251 | printk(".\n"); | ||
1252 | } | ||
1253 | |||
1254 | static void mii_display_config(struct work_struct *work) | ||
1255 | { | ||
1256 | struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task); | ||
1257 | struct net_device *dev = fep->netdev; | ||
1258 | uint status = fep->phy_status; | ||
1259 | 753 | ||
1260 | /* | 754 | platform_set_drvdata(dev, fep->mii_bus); |
1261 | ** When we get here, phy_task is already removed from | ||
1262 | ** the workqueue. It is thus safe to allow to reuse it. | ||
1263 | */ | ||
1264 | fep->mii_phy_task_queued = 0; | ||
1265 | printk("%s: config: auto-negotiation ", dev->name); | ||
1266 | |||
1267 | if (status & PHY_CONF_ANE) | ||
1268 | printk("on"); | ||
1269 | else | ||
1270 | printk("off"); | ||
1271 | 755 | ||
1272 | if (status & PHY_CONF_100FDX) | 756 | if (mdiobus_register(fep->mii_bus)) |
1273 | printk(", 100FDX"); | 757 | goto err_out_free_mdio_irq; |
1274 | if (status & PHY_CONF_100HDX) | ||
1275 | printk(", 100HDX"); | ||
1276 | if (status & PHY_CONF_10FDX) | ||
1277 | printk(", 10FDX"); | ||
1278 | if (status & PHY_CONF_10HDX) | ||
1279 | printk(", 10HDX"); | ||
1280 | if (!(status & PHY_CONF_SPMASK)) | ||
1281 | printk(", No speed/duplex selected?"); | ||
1282 | 758 | ||
1283 | if (status & PHY_CONF_LOOP) | 759 | if (fec_enet_mii_probe(dev) != 0) |
1284 | printk(", loopback enabled"); | 760 | goto err_out_unregister_bus; |
1285 | 761 | ||
1286 | printk(".\n"); | 762 | return 0; |
1287 | 763 | ||
1288 | fep->sequence_done = 1; | 764 | err_out_unregister_bus: |
765 | mdiobus_unregister(fep->mii_bus); | ||
766 | err_out_free_mdio_irq: | ||
767 | kfree(fep->mii_bus->irq); | ||
768 | err_out_free_mdiobus: | ||
769 | mdiobus_free(fep->mii_bus); | ||
770 | err_out: | ||
771 | return err; | ||
1289 | } | 772 | } |
1290 | 773 | ||
1291 | static void mii_relink(struct work_struct *work) | 774 | static void fec_enet_mii_remove(struct fec_enet_private *fep) |
1292 | { | 775 | { |
1293 | struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task); | 776 | if (fep->phy_dev) |
1294 | struct net_device *dev = fep->netdev; | 777 | phy_disconnect(fep->phy_dev); |
1295 | int duplex; | 778 | mdiobus_unregister(fep->mii_bus); |
1296 | 779 | kfree(fep->mii_bus->irq); | |
1297 | /* | 780 | mdiobus_free(fep->mii_bus); |
1298 | ** When we get here, phy_task is already removed from | ||
1299 | ** the workqueue. It is thus safe to allow to reuse it. | ||
1300 | */ | ||
1301 | fep->mii_phy_task_queued = 0; | ||
1302 | fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; | ||
1303 | mii_display_status(dev); | ||
1304 | fep->old_link = fep->link; | ||
1305 | |||
1306 | if (fep->link) { | ||
1307 | duplex = 0; | ||
1308 | if (fep->phy_status | ||
1309 | & (PHY_STAT_100FDX | PHY_STAT_10FDX)) | ||
1310 | duplex = 1; | ||
1311 | fec_restart(dev, duplex); | ||
1312 | } else | ||
1313 | fec_stop(dev); | ||
1314 | } | 781 | } |
1315 | 782 | ||
1316 | /* mii_queue_relink is called in interrupt context from mii_link_interrupt */ | 783 | static int fec_enet_get_settings(struct net_device *dev, |
1317 | static void mii_queue_relink(uint mii_reg, struct net_device *dev) | 784 | struct ethtool_cmd *cmd) |
1318 | { | 785 | { |
1319 | struct fec_enet_private *fep = netdev_priv(dev); | 786 | struct fec_enet_private *fep = netdev_priv(dev); |
787 | struct phy_device *phydev = fep->phy_dev; | ||
1320 | 788 | ||
1321 | /* | 789 | if (!phydev) |
1322 | * We cannot queue phy_task twice in the workqueue. It | 790 | return -ENODEV; |
1323 | * would cause an endless loop in the workqueue. | ||
1324 | * Fortunately, if the last mii_relink entry has not yet been | ||
1325 | * executed now, it will do the job for the current interrupt, | ||
1326 | * which is just what we want. | ||
1327 | */ | ||
1328 | if (fep->mii_phy_task_queued) | ||
1329 | return; | ||
1330 | 791 | ||
1331 | fep->mii_phy_task_queued = 1; | 792 | return phy_ethtool_gset(phydev, cmd); |
1332 | INIT_WORK(&fep->phy_task, mii_relink); | ||
1333 | schedule_work(&fep->phy_task); | ||
1334 | } | 793 | } |
1335 | 794 | ||
1336 | /* mii_queue_config is called in interrupt context from fec_enet_mii */ | 795 | static int fec_enet_set_settings(struct net_device *dev, |
1337 | static void mii_queue_config(uint mii_reg, struct net_device *dev) | 796 | struct ethtool_cmd *cmd) |
1338 | { | 797 | { |
1339 | struct fec_enet_private *fep = netdev_priv(dev); | 798 | struct fec_enet_private *fep = netdev_priv(dev); |
799 | struct phy_device *phydev = fep->phy_dev; | ||
1340 | 800 | ||
1341 | if (fep->mii_phy_task_queued) | 801 | if (!phydev) |
1342 | return; | 802 | return -ENODEV; |
1343 | 803 | ||
1344 | fep->mii_phy_task_queued = 1; | 804 | return phy_ethtool_sset(phydev, cmd); |
1345 | INIT_WORK(&fep->phy_task, mii_display_config); | ||
1346 | schedule_work(&fep->phy_task); | ||
1347 | } | 805 | } |
1348 | 806 | ||
1349 | phy_cmd_t const phy_cmd_relink[] = { | 807 | static void fec_enet_get_drvinfo(struct net_device *dev, |
1350 | { mk_mii_read(MII_REG_CR), mii_queue_relink }, | 808 | struct ethtool_drvinfo *info) |
1351 | { mk_mii_end, } | ||
1352 | }; | ||
1353 | phy_cmd_t const phy_cmd_config[] = { | ||
1354 | { mk_mii_read(MII_REG_CR), mii_queue_config }, | ||
1355 | { mk_mii_end, } | ||
1356 | }; | ||
1357 | |||
1358 | /* Read remainder of PHY ID. */ | ||
1359 | static void | ||
1360 | mii_discover_phy3(uint mii_reg, struct net_device *dev) | ||
1361 | { | 809 | { |
1362 | struct fec_enet_private *fep; | 810 | struct fec_enet_private *fep = netdev_priv(dev); |
1363 | int i; | ||
1364 | |||
1365 | fep = netdev_priv(dev); | ||
1366 | fep->phy_id |= (mii_reg & 0xffff); | ||
1367 | printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id); | ||
1368 | |||
1369 | for(i = 0; phy_info[i]; i++) { | ||
1370 | if(phy_info[i]->id == (fep->phy_id >> 4)) | ||
1371 | break; | ||
1372 | } | ||
1373 | |||
1374 | if (phy_info[i]) | ||
1375 | printk(" -- %s\n", phy_info[i]->name); | ||
1376 | else | ||
1377 | printk(" -- unknown PHY!\n"); | ||
1378 | 811 | ||
1379 | fep->phy = phy_info[i]; | 812 | strcpy(info->driver, fep->pdev->dev.driver->name); |
1380 | fep->phy_id_done = 1; | 813 | strcpy(info->version, "Revision: 1.0"); |
814 | strcpy(info->bus_info, dev_name(&dev->dev)); | ||
1381 | } | 815 | } |
1382 | 816 | ||
1383 | /* Scan all of the MII PHY addresses looking for someone to respond | 817 | static struct ethtool_ops fec_enet_ethtool_ops = { |
1384 | * with a valid ID. This usually happens quickly. | 818 | .get_settings = fec_enet_get_settings, |
1385 | */ | 819 | .set_settings = fec_enet_set_settings, |
1386 | static void | 820 | .get_drvinfo = fec_enet_get_drvinfo, |
1387 | mii_discover_phy(uint mii_reg, struct net_device *dev) | 821 | .get_link = ethtool_op_get_link, |
1388 | { | 822 | }; |
1389 | struct fec_enet_private *fep; | ||
1390 | uint phytype; | ||
1391 | |||
1392 | fep = netdev_priv(dev); | ||
1393 | |||
1394 | if (fep->phy_addr < 32) { | ||
1395 | if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { | ||
1396 | |||
1397 | /* Got first part of ID, now get remainder */ | ||
1398 | fep->phy_id = phytype << 16; | ||
1399 | mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR2), | ||
1400 | mii_discover_phy3); | ||
1401 | } else { | ||
1402 | fep->phy_addr++; | ||
1403 | mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR1), | ||
1404 | mii_discover_phy); | ||
1405 | } | ||
1406 | } else { | ||
1407 | printk("FEC: No PHY device found.\n"); | ||
1408 | /* Disable external MII interface */ | ||
1409 | writel(0, fep->hwp + FEC_MII_SPEED); | ||
1410 | fep->phy_speed = 0; | ||
1411 | #ifdef HAVE_mii_link_interrupt | ||
1412 | fec_disable_phy_intr(dev); | ||
1413 | #endif | ||
1414 | } | ||
1415 | } | ||
1416 | 823 | ||
1417 | /* This interrupt occurs when the PHY detects a link change */ | 824 | static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
1418 | #ifdef HAVE_mii_link_interrupt | ||
1419 | static irqreturn_t | ||
1420 | mii_link_interrupt(int irq, void * dev_id) | ||
1421 | { | 825 | { |
1422 | struct net_device *dev = dev_id; | ||
1423 | struct fec_enet_private *fep = netdev_priv(dev); | 826 | struct fec_enet_private *fep = netdev_priv(dev); |
827 | struct phy_device *phydev = fep->phy_dev; | ||
828 | |||
829 | if (!netif_running(dev)) | ||
830 | return -EINVAL; | ||
1424 | 831 | ||
1425 | mii_do_cmd(dev, fep->phy->ack_int); | 832 | if (!phydev) |
1426 | mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ | 833 | return -ENODEV; |
1427 | 834 | ||
1428 | return IRQ_HANDLED; | 835 | return phy_mii_ioctl(phydev, if_mii(rq), cmd); |
1429 | } | 836 | } |
1430 | #endif | ||
1431 | 837 | ||
1432 | static void fec_enet_free_buffers(struct net_device *dev) | 838 | static void fec_enet_free_buffers(struct net_device *dev) |
1433 | { | 839 | { |
@@ -1509,35 +915,8 @@ fec_enet_open(struct net_device *dev) | |||
1509 | if (ret) | 915 | if (ret) |
1510 | return ret; | 916 | return ret; |
1511 | 917 | ||
1512 | fep->sequence_done = 0; | 918 | /* schedule a link state check */ |
1513 | fep->link = 0; | 919 | phy_start(fep->phy_dev); |
1514 | |||
1515 | fec_restart(dev, 1); | ||
1516 | |||
1517 | if (fep->phy) { | ||
1518 | mii_do_cmd(dev, fep->phy->ack_int); | ||
1519 | mii_do_cmd(dev, fep->phy->config); | ||
1520 | mii_do_cmd(dev, phy_cmd_config); /* display configuration */ | ||
1521 | |||
1522 | /* Poll until the PHY tells us its configuration | ||
1523 | * (not link state). | ||
1524 | * Request is initiated by mii_do_cmd above, but answer | ||
1525 | * comes by interrupt. | ||
1526 | * This should take about 25 usec per register at 2.5 MHz, | ||
1527 | * and we read approximately 5 registers. | ||
1528 | */ | ||
1529 | while(!fep->sequence_done) | ||
1530 | schedule(); | ||
1531 | |||
1532 | mii_do_cmd(dev, fep->phy->startup); | ||
1533 | } | ||
1534 | |||
1535 | /* Set the initial link state to true. A lot of hardware | ||
1536 | * based on this device does not implement a PHY interrupt, | ||
1537 | * so we are never notified of link change. | ||
1538 | */ | ||
1539 | fep->link = 1; | ||
1540 | |||
1541 | netif_start_queue(dev); | 920 | netif_start_queue(dev); |
1542 | fep->opened = 1; | 921 | fep->opened = 1; |
1543 | return 0; | 922 | return 0; |
@@ -1550,6 +929,7 @@ fec_enet_close(struct net_device *dev) | |||
1550 | 929 | ||
1551 | /* Don't know what to do yet. */ | 930 | /* Don't know what to do yet. */ |
1552 | fep->opened = 0; | 931 | fep->opened = 0; |
932 | phy_stop(fep->phy_dev); | ||
1553 | netif_stop_queue(dev); | 933 | netif_stop_queue(dev); |
1554 | fec_stop(dev); | 934 | fec_stop(dev); |
1555 | 935 | ||
@@ -1666,6 +1046,7 @@ static const struct net_device_ops fec_netdev_ops = { | |||
1666 | .ndo_validate_addr = eth_validate_addr, | 1046 | .ndo_validate_addr = eth_validate_addr, |
1667 | .ndo_tx_timeout = fec_timeout, | 1047 | .ndo_tx_timeout = fec_timeout, |
1668 | .ndo_set_mac_address = fec_set_mac_address, | 1048 | .ndo_set_mac_address = fec_set_mac_address, |
1049 | .ndo_do_ioctl = fec_enet_ioctl, | ||
1669 | }; | 1050 | }; |
1670 | 1051 | ||
1671 | /* | 1052 | /* |
@@ -1689,7 +1070,6 @@ static int fec_enet_init(struct net_device *dev, int index) | |||
1689 | } | 1070 | } |
1690 | 1071 | ||
1691 | spin_lock_init(&fep->hw_lock); | 1072 | spin_lock_init(&fep->hw_lock); |
1692 | spin_lock_init(&fep->mii_lock); | ||
1693 | 1073 | ||
1694 | fep->index = index; | 1074 | fep->index = index; |
1695 | fep->hwp = (void __iomem *)dev->base_addr; | 1075 | fep->hwp = (void __iomem *)dev->base_addr; |
@@ -1716,20 +1096,10 @@ static int fec_enet_init(struct net_device *dev, int index) | |||
1716 | fep->rx_bd_base = cbd_base; | 1096 | fep->rx_bd_base = cbd_base; |
1717 | fep->tx_bd_base = cbd_base + RX_RING_SIZE; | 1097 | fep->tx_bd_base = cbd_base + RX_RING_SIZE; |
1718 | 1098 | ||
1719 | #ifdef HAVE_mii_link_interrupt | ||
1720 | fec_request_mii_intr(dev); | ||
1721 | #endif | ||
1722 | /* The FEC Ethernet specific entries in the device structure */ | 1099 | /* The FEC Ethernet specific entries in the device structure */ |
1723 | dev->watchdog_timeo = TX_TIMEOUT; | 1100 | dev->watchdog_timeo = TX_TIMEOUT; |
1724 | dev->netdev_ops = &fec_netdev_ops; | 1101 | dev->netdev_ops = &fec_netdev_ops; |
1725 | 1102 | dev->ethtool_ops = &fec_enet_ethtool_ops; | |
1726 | for (i=0; i<NMII-1; i++) | ||
1727 | mii_cmds[i].mii_next = &mii_cmds[i+1]; | ||
1728 | mii_free = mii_cmds; | ||
1729 | |||
1730 | /* Set MII speed to 2.5 MHz */ | ||
1731 | fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) | ||
1732 | / 2500000) / 2) & 0x3F) << 1; | ||
1733 | 1103 | ||
1734 | /* Initialize the receive buffer descriptors. */ | 1104 | /* Initialize the receive buffer descriptors. */ |
1735 | bdp = fep->rx_bd_base; | 1105 | bdp = fep->rx_bd_base; |
@@ -1760,13 +1130,6 @@ static int fec_enet_init(struct net_device *dev, int index) | |||
1760 | 1130 | ||
1761 | fec_restart(dev, 0); | 1131 | fec_restart(dev, 0); |
1762 | 1132 | ||
1763 | /* Queue up command to detect the PHY and initialize the | ||
1764 | * remainder of the interface. | ||
1765 | */ | ||
1766 | fep->phy_id_done = 0; | ||
1767 | fep->phy_addr = 0; | ||
1768 | mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); | ||
1769 | |||
1770 | return 0; | 1133 | return 0; |
1771 | } | 1134 | } |
1772 | 1135 | ||
@@ -1835,8 +1198,7 @@ fec_restart(struct net_device *dev, int duplex) | |||
1835 | writel(0, fep->hwp + FEC_R_DES_ACTIVE); | 1198 | writel(0, fep->hwp + FEC_R_DES_ACTIVE); |
1836 | 1199 | ||
1837 | /* Enable interrupts we wish to service */ | 1200 | /* Enable interrupts we wish to service */ |
1838 | writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII, | 1201 | writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK); |
1839 | fep->hwp + FEC_IMASK); | ||
1840 | } | 1202 | } |
1841 | 1203 | ||
1842 | static void | 1204 | static void |
@@ -1859,7 +1221,6 @@ fec_stop(struct net_device *dev) | |||
1859 | /* Clear outstanding MII command interrupts. */ | 1221 | /* Clear outstanding MII command interrupts. */ |
1860 | writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); | 1222 | writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); |
1861 | 1223 | ||
1862 | writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); | ||
1863 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); | 1224 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); |
1864 | } | 1225 | } |
1865 | 1226 | ||
@@ -1891,6 +1252,7 @@ fec_probe(struct platform_device *pdev) | |||
1891 | memset(fep, 0, sizeof(*fep)); | 1252 | memset(fep, 0, sizeof(*fep)); |
1892 | 1253 | ||
1893 | ndev->base_addr = (unsigned long)ioremap(r->start, resource_size(r)); | 1254 | ndev->base_addr = (unsigned long)ioremap(r->start, resource_size(r)); |
1255 | fep->pdev = pdev; | ||
1894 | 1256 | ||
1895 | if (!ndev->base_addr) { | 1257 | if (!ndev->base_addr) { |
1896 | ret = -ENOMEM; | 1258 | ret = -ENOMEM; |
@@ -1926,13 +1288,24 @@ fec_probe(struct platform_device *pdev) | |||
1926 | if (ret) | 1288 | if (ret) |
1927 | goto failed_init; | 1289 | goto failed_init; |
1928 | 1290 | ||
1291 | ret = fec_enet_mii_init(pdev); | ||
1292 | if (ret) | ||
1293 | goto failed_mii_init; | ||
1294 | |||
1929 | ret = register_netdev(ndev); | 1295 | ret = register_netdev(ndev); |
1930 | if (ret) | 1296 | if (ret) |
1931 | goto failed_register; | 1297 | goto failed_register; |
1932 | 1298 | ||
1299 | printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] " | ||
1300 | "(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name, | ||
1301 | fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), | ||
1302 | fep->phy_dev->irq); | ||
1303 | |||
1933 | return 0; | 1304 | return 0; |
1934 | 1305 | ||
1935 | failed_register: | 1306 | failed_register: |
1307 | fec_enet_mii_remove(fep); | ||
1308 | failed_mii_init: | ||
1936 | failed_init: | 1309 | failed_init: |
1937 | clk_disable(fep->clk); | 1310 | clk_disable(fep->clk); |
1938 | clk_put(fep->clk); | 1311 | clk_put(fep->clk); |
@@ -1959,6 +1332,7 @@ fec_drv_remove(struct platform_device *pdev) | |||
1959 | platform_set_drvdata(pdev, NULL); | 1332 | platform_set_drvdata(pdev, NULL); |
1960 | 1333 | ||
1961 | fec_stop(ndev); | 1334 | fec_stop(ndev); |
1335 | fec_enet_mii_remove(fep); | ||
1962 | clk_disable(fep->clk); | 1336 | clk_disable(fep->clk); |
1963 | clk_put(fep->clk); | 1337 | clk_put(fep->clk); |
1964 | iounmap((void __iomem *)ndev->base_addr); | 1338 | iounmap((void __iomem *)ndev->base_addr); |