diff options
| author | Vitaly Bordug <vbordug@ru.mvista.com> | 2006-08-15 02:00:30 -0400 |
|---|---|---|
| committer | Jeff Garzik <jeff@garzik.org> | 2006-08-19 17:44:31 -0400 |
| commit | 5b4b8454344a0391bb0f69fda0f4ec8e1f0d2fed (patch) | |
| tree | a5e662cdc03d319e56a277281dcde754150276f4 /drivers/net | |
| parent | 11b0bacd717c285c94dbb56505a28434b34f0639 (diff) | |
[PATCH] FS_ENET: use PAL for mii management
This patch should update the fs_enet infrastructure to utilize Phy Abstraction
Layer subsystem. Along with the above, there are apparent bugfixes, overhaul
and improvements.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/fs_enet/Makefile | 6 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fec.h | 42 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 207 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fs_enet-mii.c | 505 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fs_enet.h | 40 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mac-fcc.c | 32 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mac-fec.c | 142 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mac-scc.c | 4 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mii-bitbang.c | 448 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mii-fec.c | 243 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mii-fixed.c | 91 |
11 files changed, 711 insertions, 1049 deletions
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile index d6dd3f2fb43e..02d4dc18ba69 100644 --- a/drivers/net/fs_enet/Makefile +++ b/drivers/net/fs_enet/Makefile | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_FS_ENET) += fs_enet.o | 5 | obj-$(CONFIG_FS_ENET) += fs_enet.o |
| 6 | 6 | ||
| 7 | obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o | 7 | obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o |
| 8 | obj-$(CONFIG_8260) += mac-fcc.o | 8 | obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o |
| 9 | 9 | ||
| 10 | fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o | 10 | fs_enet-objs := fs_enet-main.o |
diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/fs_enet/fec.h new file mode 100644 index 000000000000..e980527e2b99 --- /dev/null +++ b/drivers/net/fs_enet/fec.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #ifndef FS_ENET_FEC_H | ||
| 2 | #define FS_ENET_FEC_H | ||
| 3 | |||
| 4 | /* CRC polynomium used by the FEC for the multicast group filtering */ | ||
| 5 | #define FEC_CRC_POLY 0x04C11DB7 | ||
| 6 | |||
| 7 | #define FEC_MAX_MULTICAST_ADDRS 64 | ||
| 8 | |||
| 9 | /* Interrupt events/masks. | ||
| 10 | */ | ||
| 11 | #define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ | ||
| 12 | #define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ | ||
| 13 | #define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ | ||
| 14 | #define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ | ||
| 15 | #define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ | ||
| 16 | #define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ | ||
| 17 | #define FEC_ENET_RXF 0x02000000U /* Full frame received */ | ||
| 18 | #define FEC_ENET_RXB 0x01000000U /* A buffer was received */ | ||
| 19 | #define FEC_ENET_MII 0x00800000U /* MII interrupt */ | ||
| 20 | #define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ | ||
| 21 | |||
| 22 | #define FEC_ECNTRL_PINMUX 0x00000004 | ||
| 23 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
| 24 | #define FEC_ECNTRL_RESET 0x00000001 | ||
| 25 | |||
| 26 | #define FEC_RCNTRL_BC_REJ 0x00000010 | ||
| 27 | #define FEC_RCNTRL_PROM 0x00000008 | ||
| 28 | #define FEC_RCNTRL_MII_MODE 0x00000004 | ||
| 29 | #define FEC_RCNTRL_DRT 0x00000002 | ||
| 30 | #define FEC_RCNTRL_LOOP 0x00000001 | ||
| 31 | |||
| 32 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
| 33 | #define FEC_TCNTRL_HBC 0x00000002 | ||
| 34 | #define FEC_TCNTRL_GTS 0x00000001 | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* | ||
| 39 | * Delay to wait for FEC reset command to complete (in us) | ||
| 40 | */ | ||
| 41 | #define FEC_RESET_DELAY 50 | ||
| 42 | #endif | ||
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f6abff5846b3..df62506a1787 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/bitops.h> | 37 | #include <linux/bitops.h> |
| 38 | #include <linux/fs.h> | 38 | #include <linux/fs.h> |
| 39 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
| 40 | #include <linux/phy.h> | ||
| 40 | 41 | ||
| 41 | #include <linux/vmalloc.h> | 42 | #include <linux/vmalloc.h> |
| 42 | #include <asm/pgtable.h> | 43 | #include <asm/pgtable.h> |
| @@ -682,35 +683,6 @@ static void fs_free_irq(struct net_device *dev, int irq) | |||
| 682 | (*fep->ops->post_free_irq)(dev, irq); | 683 | (*fep->ops->post_free_irq)(dev, irq); |
| 683 | } | 684 | } |
| 684 | 685 | ||
| 685 | /**********************************************************************************/ | ||
| 686 | |||
| 687 | /* This interrupt occurs when the PHY detects a link change. */ | ||
| 688 | static irqreturn_t | ||
| 689 | fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 690 | { | ||
| 691 | struct net_device *dev = dev_id; | ||
| 692 | struct fs_enet_private *fep; | ||
| 693 | const struct fs_platform_info *fpi; | ||
| 694 | |||
| 695 | fep = netdev_priv(dev); | ||
| 696 | fpi = fep->fpi; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * Acknowledge the interrupt if possible. If we have not | ||
| 700 | * found the PHY yet we can't process or acknowledge the | ||
| 701 | * interrupt now. Instead we ignore this interrupt for now, | ||
| 702 | * which we can do since it is edge triggered. It will be | ||
| 703 | * acknowledged later by fs_enet_open(). | ||
| 704 | */ | ||
| 705 | if (!fep->phy) | ||
| 706 | return IRQ_NONE; | ||
| 707 | |||
| 708 | fs_mii_ack_int(dev); | ||
| 709 | fs_mii_link_status_change_check(dev, 0); | ||
| 710 | |||
| 711 | return IRQ_HANDLED; | ||
| 712 | } | ||
| 713 | |||
| 714 | static void fs_timeout(struct net_device *dev) | 686 | static void fs_timeout(struct net_device *dev) |
| 715 | { | 687 | { |
| 716 | struct fs_enet_private *fep = netdev_priv(dev); | 688 | struct fs_enet_private *fep = netdev_priv(dev); |
| @@ -722,10 +694,13 @@ static void fs_timeout(struct net_device *dev) | |||
| 722 | spin_lock_irqsave(&fep->lock, flags); | 694 | spin_lock_irqsave(&fep->lock, flags); |
| 723 | 695 | ||
| 724 | if (dev->flags & IFF_UP) { | 696 | if (dev->flags & IFF_UP) { |
| 697 | phy_stop(fep->phydev); | ||
| 725 | (*fep->ops->stop)(dev); | 698 | (*fep->ops->stop)(dev); |
| 726 | (*fep->ops->restart)(dev); | 699 | (*fep->ops->restart)(dev); |
| 700 | phy_start(fep->phydev); | ||
| 727 | } | 701 | } |
| 728 | 702 | ||
| 703 | phy_start(fep->phydev); | ||
| 729 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); | 704 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); |
| 730 | spin_unlock_irqrestore(&fep->lock, flags); | 705 | spin_unlock_irqrestore(&fep->lock, flags); |
| 731 | 706 | ||
| @@ -733,35 +708,112 @@ static void fs_timeout(struct net_device *dev) | |||
| 733 | netif_wake_queue(dev); | 708 | netif_wake_queue(dev); |
| 734 | } | 709 | } |
| 735 | 710 | ||
| 711 | /*----------------------------------------------------------------------------- | ||
| 712 | * generic link-change handler - should be sufficient for most cases | ||
| 713 | *-----------------------------------------------------------------------------*/ | ||
| 714 | static void generic_adjust_link(struct net_device *dev) | ||
| 715 | { | ||
| 716 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 717 | struct phy_device *phydev = fep->phydev; | ||
| 718 | int new_state = 0; | ||
| 719 | |||
| 720 | if (phydev->link) { | ||
| 721 | |||
| 722 | /* adjust to duplex mode */ | ||
| 723 | if (phydev->duplex != fep->oldduplex){ | ||
| 724 | new_state = 1; | ||
| 725 | fep->oldduplex = phydev->duplex; | ||
| 726 | } | ||
| 727 | |||
| 728 | if (phydev->speed != fep->oldspeed) { | ||
| 729 | new_state = 1; | ||
| 730 | fep->oldspeed = phydev->speed; | ||
| 731 | } | ||
| 732 | |||
| 733 | if (!fep->oldlink) { | ||
| 734 | new_state = 1; | ||
| 735 | fep->oldlink = 1; | ||
| 736 | netif_schedule(dev); | ||
| 737 | netif_carrier_on(dev); | ||
| 738 | netif_start_queue(dev); | ||
| 739 | } | ||
| 740 | |||
| 741 | if (new_state) | ||
| 742 | fep->ops->restart(dev); | ||
| 743 | |||
| 744 | } else if (fep->oldlink) { | ||
| 745 | new_state = 1; | ||
| 746 | fep->oldlink = 0; | ||
| 747 | fep->oldspeed = 0; | ||
| 748 | fep->oldduplex = -1; | ||
| 749 | netif_carrier_off(dev); | ||
| 750 | netif_stop_queue(dev); | ||
| 751 | } | ||
| 752 | |||
| 753 | if (new_state && netif_msg_link(fep)) | ||
| 754 | phy_print_status(phydev); | ||
| 755 | } | ||
| 756 | |||
| 757 | |||
| 758 | static void fs_adjust_link(struct net_device *dev) | ||
| 759 | { | ||
| 760 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 761 | unsigned long flags; | ||
| 762 | |||
| 763 | spin_lock_irqsave(&fep->lock, flags); | ||
| 764 | |||
| 765 | if(fep->ops->adjust_link) | ||
| 766 | fep->ops->adjust_link(dev); | ||
| 767 | else | ||
| 768 | generic_adjust_link(dev); | ||
| 769 | |||
| 770 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 771 | } | ||
| 772 | |||
| 773 | static int fs_init_phy(struct net_device *dev) | ||
| 774 | { | ||
| 775 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 776 | struct phy_device *phydev; | ||
| 777 | |||
| 778 | fep->oldlink = 0; | ||
| 779 | fep->oldspeed = 0; | ||
| 780 | fep->oldduplex = -1; | ||
| 781 | if(fep->fpi->bus_id) | ||
| 782 | phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); | ||
| 783 | else { | ||
| 784 | printk("No phy bus ID specified in BSP code\n"); | ||
| 785 | return -EINVAL; | ||
| 786 | } | ||
| 787 | if (IS_ERR(phydev)) { | ||
| 788 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | ||
| 789 | return PTR_ERR(phydev); | ||
| 790 | } | ||
| 791 | |||
| 792 | fep->phydev = phydev; | ||
| 793 | |||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | |||
| 736 | static int fs_enet_open(struct net_device *dev) | 798 | static int fs_enet_open(struct net_device *dev) |
| 737 | { | 799 | { |
| 738 | struct fs_enet_private *fep = netdev_priv(dev); | 800 | struct fs_enet_private *fep = netdev_priv(dev); |
| 739 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 740 | int r; | 801 | int r; |
| 802 | int err; | ||
| 741 | 803 | ||
| 742 | /* Install our interrupt handler. */ | 804 | /* Install our interrupt handler. */ |
| 743 | r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); | 805 | r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); |
| 744 | if (r != 0) { | 806 | if (r != 0) { |
| 745 | printk(KERN_ERR DRV_MODULE_NAME | 807 | printk(KERN_ERR DRV_MODULE_NAME |
| 746 | ": %s Could not allocate FEC IRQ!", dev->name); | 808 | ": %s Could not allocate FS_ENET IRQ!", dev->name); |
| 747 | return -EINVAL; | 809 | return -EINVAL; |
| 748 | } | 810 | } |
| 749 | 811 | ||
| 750 | /* Install our phy interrupt handler */ | 812 | err = fs_init_phy(dev); |
| 751 | if (fpi->phy_irq != -1) { | 813 | if(err) |
| 752 | 814 | return err; | |
| 753 | r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); | ||
| 754 | if (r != 0) { | ||
| 755 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 756 | ": %s Could not allocate PHY IRQ!", dev->name); | ||
| 757 | fs_free_irq(dev, fep->interrupt); | ||
| 758 | return -EINVAL; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | 815 | ||
| 762 | fs_mii_startup(dev); | 816 | phy_start(fep->phydev); |
| 763 | netif_carrier_off(dev); | ||
| 764 | fs_mii_link_status_change_check(dev, 1); | ||
| 765 | 817 | ||
| 766 | return 0; | 818 | return 0; |
| 767 | } | 819 | } |
| @@ -769,20 +821,19 @@ static int fs_enet_open(struct net_device *dev) | |||
| 769 | static int fs_enet_close(struct net_device *dev) | 821 | static int fs_enet_close(struct net_device *dev) |
| 770 | { | 822 | { |
| 771 | struct fs_enet_private *fep = netdev_priv(dev); | 823 | struct fs_enet_private *fep = netdev_priv(dev); |
| 772 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 773 | unsigned long flags; | 824 | unsigned long flags; |
| 774 | 825 | ||
| 775 | netif_stop_queue(dev); | 826 | netif_stop_queue(dev); |
| 776 | netif_carrier_off(dev); | 827 | netif_carrier_off(dev); |
| 777 | fs_mii_shutdown(dev); | 828 | phy_stop(fep->phydev); |
| 778 | 829 | ||
| 779 | spin_lock_irqsave(&fep->lock, flags); | 830 | spin_lock_irqsave(&fep->lock, flags); |
| 780 | (*fep->ops->stop)(dev); | 831 | (*fep->ops->stop)(dev); |
| 781 | spin_unlock_irqrestore(&fep->lock, flags); | 832 | spin_unlock_irqrestore(&fep->lock, flags); |
| 782 | 833 | ||
| 783 | /* release any irqs */ | 834 | /* release any irqs */ |
| 784 | if (fpi->phy_irq != -1) | 835 | phy_disconnect(fep->phydev); |
| 785 | fs_free_irq(dev, fpi->phy_irq); | 836 | fep->phydev = NULL; |
| 786 | fs_free_irq(dev, fep->interrupt); | 837 | fs_free_irq(dev, fep->interrupt); |
| 787 | 838 | ||
| 788 | return 0; | 839 | return 0; |
| @@ -830,33 +881,19 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
| 830 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 881 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
| 831 | { | 882 | { |
| 832 | struct fs_enet_private *fep = netdev_priv(dev); | 883 | struct fs_enet_private *fep = netdev_priv(dev); |
| 833 | unsigned long flags; | 884 | return phy_ethtool_gset(fep->phydev, cmd); |
| 834 | int rc; | ||
| 835 | |||
| 836 | spin_lock_irqsave(&fep->lock, flags); | ||
| 837 | rc = mii_ethtool_gset(&fep->mii_if, cmd); | ||
| 838 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 839 | |||
| 840 | return rc; | ||
| 841 | } | 885 | } |
| 842 | 886 | ||
| 843 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 887 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
| 844 | { | 888 | { |
| 845 | struct fs_enet_private *fep = netdev_priv(dev); | 889 | struct fs_enet_private *fep = netdev_priv(dev); |
| 846 | unsigned long flags; | 890 | phy_ethtool_sset(fep->phydev, cmd); |
| 847 | int rc; | 891 | return 0; |
| 848 | |||
| 849 | spin_lock_irqsave(&fep->lock, flags); | ||
| 850 | rc = mii_ethtool_sset(&fep->mii_if, cmd); | ||
| 851 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 852 | |||
| 853 | return rc; | ||
| 854 | } | 892 | } |
| 855 | 893 | ||
| 856 | static int fs_nway_reset(struct net_device *dev) | 894 | static int fs_nway_reset(struct net_device *dev) |
| 857 | { | 895 | { |
| 858 | struct fs_enet_private *fep = netdev_priv(dev); | 896 | return 0; |
| 859 | return mii_nway_restart(&fep->mii_if); | ||
| 860 | } | 897 | } |
| 861 | 898 | ||
| 862 | static u32 fs_get_msglevel(struct net_device *dev) | 899 | static u32 fs_get_msglevel(struct net_device *dev) |
| @@ -898,7 +935,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
| 898 | return -EINVAL; | 935 | return -EINVAL; |
| 899 | 936 | ||
| 900 | spin_lock_irqsave(&fep->lock, flags); | 937 | spin_lock_irqsave(&fep->lock, flags); |
| 901 | rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); | 938 | rc = phy_mii_ioctl(fep->phydev, mii, cmd); |
| 902 | spin_unlock_irqrestore(&fep->lock, flags); | 939 | spin_unlock_irqrestore(&fep->lock, flags); |
| 903 | return rc; | 940 | return rc; |
| 904 | } | 941 | } |
| @@ -1030,12 +1067,6 @@ static struct net_device *fs_init_instance(struct device *dev, | |||
| 1030 | } | 1067 | } |
| 1031 | registered = 1; | 1068 | registered = 1; |
| 1032 | 1069 | ||
| 1033 | err = fs_mii_connect(ndev); | ||
| 1034 | if (err != 0) { | ||
| 1035 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 1036 | ": %s fs_mii_connect failed.\n", ndev->name); | ||
| 1037 | goto err; | ||
| 1038 | } | ||
| 1039 | 1070 | ||
| 1040 | return ndev; | 1071 | return ndev; |
| 1041 | 1072 | ||
| @@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct net_device *ndev) | |||
| 1073 | 1104 | ||
| 1074 | fpi = fep->fpi; | 1105 | fpi = fep->fpi; |
| 1075 | 1106 | ||
| 1076 | fs_mii_disconnect(ndev); | ||
| 1077 | |||
| 1078 | unregister_netdev(ndev); | 1107 | unregister_netdev(ndev); |
| 1079 | 1108 | ||
| 1080 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | 1109 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), |
| @@ -1196,17 +1225,39 @@ static int __init fs_init(void) | |||
| 1196 | r = setup_immap(); | 1225 | r = setup_immap(); |
| 1197 | if (r != 0) | 1226 | if (r != 0) |
| 1198 | return r; | 1227 | return r; |
| 1199 | r = driver_register(&fs_enet_fec_driver); | 1228 | |
| 1229 | #ifdef CONFIG_FS_ENET_HAS_FCC | ||
| 1230 | /* let's insert mii stuff */ | ||
| 1231 | r = fs_enet_mdio_bb_init(); | ||
| 1232 | |||
| 1233 | if (r != 0) { | ||
| 1234 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 1235 | "BB PHY init failed.\n"); | ||
| 1236 | return r; | ||
| 1237 | } | ||
| 1238 | r = driver_register(&fs_enet_fcc_driver); | ||
| 1200 | if (r != 0) | 1239 | if (r != 0) |
| 1201 | goto err; | 1240 | goto err; |
| 1241 | #endif | ||
| 1202 | 1242 | ||
| 1203 | r = driver_register(&fs_enet_fcc_driver); | 1243 | #ifdef CONFIG_FS_ENET_HAS_FEC |
| 1244 | r = fs_enet_mdio_fec_init(); | ||
| 1245 | if (r != 0) { | ||
| 1246 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 1247 | "FEC PHY init failed.\n"); | ||
| 1248 | return r; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | r = driver_register(&fs_enet_fec_driver); | ||
| 1204 | if (r != 0) | 1252 | if (r != 0) |
| 1205 | goto err; | 1253 | goto err; |
| 1254 | #endif | ||
| 1206 | 1255 | ||
| 1256 | #ifdef CONFIG_FS_ENET_HAS_SCC | ||
| 1207 | r = driver_register(&fs_enet_scc_driver); | 1257 | r = driver_register(&fs_enet_scc_driver); |
| 1208 | if (r != 0) | 1258 | if (r != 0) |
| 1209 | goto err; | 1259 | goto err; |
| 1260 | #endif | ||
| 1210 | 1261 | ||
| 1211 | return 0; | 1262 | return 0; |
| 1212 | err: | 1263 | err: |
diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c deleted file mode 100644 index b7e6e21725cb..000000000000 --- a/drivers/net/fs_enet/fs_enet-mii.c +++ /dev/null | |||
| @@ -1,505 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> | ||
| 11 | * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> | ||
| 12 | * | ||
| 13 | * This file is licensed under the terms of the GNU General Public License | ||
| 14 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 15 | * kind, whether express or implied. | ||
| 16 | */ | ||
| 17 | |||
| 18 | |||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/sched.h> | ||
| 23 | #include <linux/string.h> | ||
| 24 | #include <linux/ptrace.h> | ||
| 25 | #include <linux/errno.h> | ||
| 26 | #include <linux/ioport.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/interrupt.h> | ||
| 29 | #include <linux/pci.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/netdevice.h> | ||
| 33 | #include <linux/etherdevice.h> | ||
| 34 | #include <linux/skbuff.h> | ||
| 35 | #include <linux/spinlock.h> | ||
| 36 | #include <linux/mii.h> | ||
| 37 | #include <linux/ethtool.h> | ||
| 38 | #include <linux/bitops.h> | ||
| 39 | |||
| 40 | #include <asm/pgtable.h> | ||
| 41 | #include <asm/irq.h> | ||
| 42 | #include <asm/uaccess.h> | ||
| 43 | |||
| 44 | #include "fs_enet.h" | ||
| 45 | |||
| 46 | /*************************************************/ | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Generic PHY support. | ||
| 50 | * Should work for all PHYs, but link change is detected by polling | ||
| 51 | */ | ||
| 52 | |||
| 53 | static void generic_timer_callback(unsigned long data) | ||
| 54 | { | ||
| 55 | struct net_device *dev = (struct net_device *)data; | ||
| 56 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 57 | |||
| 58 | fep->phy_timer_list.expires = jiffies + HZ / 2; | ||
| 59 | |||
| 60 | add_timer(&fep->phy_timer_list); | ||
| 61 | |||
| 62 | fs_mii_link_status_change_check(dev, 0); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void generic_startup(struct net_device *dev) | ||
| 66 | { | ||
| 67 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 68 | |||
| 69 | fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ | ||
| 70 | fep->phy_timer_list.data = (unsigned long)dev; | ||
| 71 | fep->phy_timer_list.function = generic_timer_callback; | ||
| 72 | add_timer(&fep->phy_timer_list); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void generic_shutdown(struct net_device *dev) | ||
| 76 | { | ||
| 77 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 78 | |||
| 79 | del_timer_sync(&fep->phy_timer_list); | ||
| 80 | } | ||
| 81 | |||
| 82 | /* ------------------------------------------------------------------------- */ | ||
| 83 | /* The Davicom DM9161 is used on the NETTA board */ | ||
| 84 | |||
| 85 | /* register definitions */ | ||
| 86 | |||
| 87 | #define MII_DM9161_ANAR 4 /* Aux. Config Register */ | ||
| 88 | #define MII_DM9161_ACR 16 /* Aux. Config Register */ | ||
| 89 | #define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ | ||
| 90 | #define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ | ||
| 91 | #define MII_DM9161_INTR 21 /* Interrupt Register */ | ||
| 92 | #define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ | ||
| 93 | #define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ | ||
| 94 | |||
| 95 | static void dm9161_startup(struct net_device *dev) | ||
| 96 | { | ||
| 97 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 98 | |||
| 99 | fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); | ||
| 100 | /* Start autonegotiation */ | ||
| 101 | fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200); | ||
| 102 | |||
| 103 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 104 | schedule_timeout(HZ*8); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void dm9161_ack_int(struct net_device *dev) | ||
| 108 | { | ||
| 109 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 110 | |||
| 111 | fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void dm9161_shutdown(struct net_device *dev) | ||
| 115 | { | ||
| 116 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 117 | |||
| 118 | fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); | ||
| 119 | } | ||
| 120 | |||
| 121 | /**********************************************************************************/ | ||
| 122 | |||
| 123 | static const struct phy_info phy_info[] = { | ||
| 124 | { | ||
| 125 | .id = 0x00181b88, | ||
| 126 | .name = "DM9161", | ||
| 127 | .startup = dm9161_startup, | ||
| 128 | .ack_int = dm9161_ack_int, | ||
| 129 | .shutdown = dm9161_shutdown, | ||
| 130 | }, { | ||
| 131 | .id = 0, | ||
| 132 | .name = "GENERIC", | ||
| 133 | .startup = generic_startup, | ||
| 134 | .shutdown = generic_shutdown, | ||
| 135 | }, | ||
| 136 | }; | ||
| 137 | |||
| 138 | /**********************************************************************************/ | ||
| 139 | |||
| 140 | static int phy_id_detect(struct net_device *dev) | ||
| 141 | { | ||
| 142 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 143 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 144 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
| 145 | int i, r, start, end, phytype, physubtype; | ||
| 146 | const struct phy_info *phy; | ||
| 147 | int phy_hwid, phy_id; | ||
| 148 | |||
| 149 | phy_hwid = -1; | ||
| 150 | fep->phy = NULL; | ||
| 151 | |||
| 152 | /* auto-detect? */ | ||
| 153 | if (fpi->phy_addr == -1) { | ||
| 154 | start = 1; | ||
| 155 | end = 32; | ||
| 156 | } else { /* direct */ | ||
| 157 | start = fpi->phy_addr; | ||
| 158 | end = start + 1; | ||
| 159 | } | ||
| 160 | |||
| 161 | for (phy_id = start; phy_id < end; phy_id++) { | ||
| 162 | /* skip already used phy addresses on this bus */ | ||
| 163 | if (bus->usage_map & (1 << phy_id)) | ||
| 164 | continue; | ||
| 165 | r = fs_mii_read(dev, phy_id, MII_PHYSID1); | ||
| 166 | if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) | ||
| 167 | continue; | ||
| 168 | r = fs_mii_read(dev, phy_id, MII_PHYSID2); | ||
| 169 | if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) | ||
| 170 | continue; | ||
| 171 | phy_hwid = (phytype << 16) | physubtype; | ||
| 172 | if (phy_hwid != -1) | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | |||
| 176 | if (phy_hwid == -1) { | ||
| 177 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 178 | ": %s No PHY detected! range=0x%02x-0x%02x\n", | ||
| 179 | dev->name, start, end); | ||
| 180 | return -1; | ||
| 181 | } | ||
| 182 | |||
| 183 | for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) | ||
| 184 | if (phy->id == (phy_hwid >> 4) || phy->id == 0) | ||
| 185 | break; | ||
| 186 | |||
| 187 | if (i >= ARRAY_SIZE(phy_info)) { | ||
| 188 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 189 | ": %s PHY id 0x%08x is not supported!\n", | ||
| 190 | dev->name, phy_hwid); | ||
| 191 | return -1; | ||
| 192 | } | ||
| 193 | |||
| 194 | fep->phy = phy; | ||
| 195 | |||
| 196 | /* mark this address as used */ | ||
| 197 | bus->usage_map |= (1 << phy_id); | ||
| 198 | |||
| 199 | printk(KERN_INFO DRV_MODULE_NAME | ||
| 200 | ": %s Phy @ 0x%x, type %s (0x%08x)%s\n", | ||
| 201 | dev->name, phy_id, fep->phy->name, phy_hwid, | ||
| 202 | fpi->phy_addr == -1 ? " (auto-detected)" : ""); | ||
| 203 | |||
| 204 | return phy_id; | ||
| 205 | } | ||
| 206 | |||
| 207 | void fs_mii_startup(struct net_device *dev) | ||
| 208 | { | ||
| 209 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 210 | |||
| 211 | if (fep->phy->startup) | ||
| 212 | (*fep->phy->startup) (dev); | ||
| 213 | } | ||
| 214 | |||
| 215 | void fs_mii_shutdown(struct net_device *dev) | ||
| 216 | { | ||
| 217 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 218 | |||
| 219 | if (fep->phy->shutdown) | ||
| 220 | (*fep->phy->shutdown) (dev); | ||
| 221 | } | ||
| 222 | |||
| 223 | void fs_mii_ack_int(struct net_device *dev) | ||
| 224 | { | ||
| 225 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 226 | |||
| 227 | if (fep->phy->ack_int) | ||
| 228 | (*fep->phy->ack_int) (dev); | ||
| 229 | } | ||
| 230 | |||
| 231 | #define MII_LINK 0x0001 | ||
| 232 | #define MII_HALF 0x0002 | ||
| 233 | #define MII_FULL 0x0004 | ||
| 234 | #define MII_BASE4 0x0008 | ||
| 235 | #define MII_10M 0x0010 | ||
| 236 | #define MII_100M 0x0020 | ||
| 237 | #define MII_1G 0x0040 | ||
| 238 | #define MII_10G 0x0080 | ||
| 239 | |||
| 240 | /* return full mii info at one gulp, with a usable form */ | ||
| 241 | static unsigned int mii_full_status(struct mii_if_info *mii) | ||
| 242 | { | ||
| 243 | unsigned int status; | ||
| 244 | int bmsr, adv, lpa, neg; | ||
| 245 | struct fs_enet_private* fep = netdev_priv(mii->dev); | ||
| 246 | |||
| 247 | /* first, a dummy read, needed to latch some MII phys */ | ||
| 248 | (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); | ||
| 249 | bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); | ||
| 250 | |||
| 251 | /* no link */ | ||
| 252 | if ((bmsr & BMSR_LSTATUS) == 0) | ||
| 253 | return 0; | ||
| 254 | |||
| 255 | status = MII_LINK; | ||
| 256 | |||
| 257 | /* Lets look what ANEG says if it's supported - otherwize we shall | ||
| 258 | take the right values from the platform info*/ | ||
| 259 | if(!mii->force_media) { | ||
| 260 | /* autoneg not completed; don't bother */ | ||
| 261 | if ((bmsr & BMSR_ANEGCOMPLETE) == 0) | ||
| 262 | return 0; | ||
| 263 | |||
| 264 | adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE); | ||
| 265 | lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA); | ||
| 266 | |||
| 267 | neg = lpa & adv; | ||
| 268 | } else { | ||
| 269 | neg = fep->fpi->bus_info->lpa; | ||
| 270 | } | ||
| 271 | |||
| 272 | if (neg & LPA_100FULL) | ||
| 273 | status |= MII_FULL | MII_100M; | ||
| 274 | else if (neg & LPA_100BASE4) | ||
| 275 | status |= MII_FULL | MII_BASE4 | MII_100M; | ||
| 276 | else if (neg & LPA_100HALF) | ||
| 277 | status |= MII_HALF | MII_100M; | ||
| 278 | else if (neg & LPA_10FULL) | ||
| 279 | status |= MII_FULL | MII_10M; | ||
| 280 | else | ||
| 281 | status |= MII_HALF | MII_10M; | ||
| 282 | |||
| 283 | return status; | ||
| 284 | } | ||
| 285 | |||
| 286 | void fs_mii_link_status_change_check(struct net_device *dev, int init_media) | ||
| 287 | { | ||
| 288 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 289 | struct mii_if_info *mii = &fep->mii_if; | ||
| 290 | unsigned int mii_status; | ||
| 291 | int ok_to_print, link, duplex, speed; | ||
| 292 | unsigned long flags; | ||
| 293 | |||
| 294 | ok_to_print = netif_msg_link(fep); | ||
| 295 | |||
| 296 | mii_status = mii_full_status(mii); | ||
| 297 | |||
| 298 | if (!init_media && mii_status == fep->last_mii_status) | ||
| 299 | return; | ||
| 300 | |||
| 301 | fep->last_mii_status = mii_status; | ||
| 302 | |||
| 303 | link = !!(mii_status & MII_LINK); | ||
| 304 | duplex = !!(mii_status & MII_FULL); | ||
| 305 | speed = (mii_status & MII_100M) ? 100 : 10; | ||
| 306 | |||
| 307 | if (link == 0) { | ||
| 308 | netif_carrier_off(mii->dev); | ||
| 309 | netif_stop_queue(dev); | ||
| 310 | if (!init_media) { | ||
| 311 | spin_lock_irqsave(&fep->lock, flags); | ||
| 312 | (*fep->ops->stop)(dev); | ||
| 313 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 314 | } | ||
| 315 | |||
| 316 | if (ok_to_print) | ||
| 317 | printk(KERN_INFO "%s: link down\n", mii->dev->name); | ||
| 318 | |||
| 319 | } else { | ||
| 320 | |||
| 321 | mii->full_duplex = duplex; | ||
| 322 | |||
| 323 | netif_carrier_on(mii->dev); | ||
| 324 | |||
| 325 | spin_lock_irqsave(&fep->lock, flags); | ||
| 326 | fep->duplex = duplex; | ||
| 327 | fep->speed = speed; | ||
| 328 | (*fep->ops->restart)(dev); | ||
| 329 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 330 | |||
| 331 | netif_start_queue(dev); | ||
| 332 | |||
| 333 | if (ok_to_print) | ||
| 334 | printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n", | ||
| 335 | dev->name, speed, duplex ? "full" : "half"); | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | /**********************************************************************************/ | ||
| 340 | |||
| 341 | int fs_mii_read(struct net_device *dev, int phy_id, int location) | ||
| 342 | { | ||
| 343 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 344 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
| 345 | |||
| 346 | unsigned long flags; | ||
| 347 | int ret; | ||
| 348 | |||
| 349 | spin_lock_irqsave(&bus->mii_lock, flags); | ||
| 350 | ret = (*bus->mii_read)(bus, phy_id, location); | ||
| 351 | spin_unlock_irqrestore(&bus->mii_lock, flags); | ||
| 352 | |||
| 353 | return ret; | ||
| 354 | } | ||
| 355 | |||
| 356 | void fs_mii_write(struct net_device *dev, int phy_id, int location, int value) | ||
| 357 | { | ||
| 358 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 359 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
| 360 | unsigned long flags; | ||
| 361 | |||
| 362 | spin_lock_irqsave(&bus->mii_lock, flags); | ||
| 363 | (*bus->mii_write)(bus, phy_id, location, value); | ||
| 364 | spin_unlock_irqrestore(&bus->mii_lock, flags); | ||
| 365 | } | ||
| 366 | |||
| 367 | /*****************************************************************************/ | ||
| 368 | |||
| 369 | /* list of all registered mii buses */ | ||
| 370 | static LIST_HEAD(fs_mii_bus_list); | ||
| 371 | |||
| 372 | static struct fs_enet_mii_bus *lookup_bus(int method, int id) | ||
| 373 | { | ||
| 374 | struct list_head *ptr; | ||
| 375 | struct fs_enet_mii_bus *bus; | ||
| 376 | |||
| 377 | list_for_each(ptr, &fs_mii_bus_list) { | ||
| 378 | bus = list_entry(ptr, struct fs_enet_mii_bus, list); | ||
| 379 | if (bus->bus_info->method == method && | ||
| 380 | bus->bus_info->id == id) | ||
| 381 | return bus; | ||
| 382 | } | ||
| 383 | return NULL; | ||
| 384 | } | ||
| 385 | |||
| 386 | static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) | ||
| 387 | { | ||
| 388 | struct fs_enet_mii_bus *bus; | ||
| 389 | int ret = 0; | ||
| 390 | |||
| 391 | bus = kmalloc(sizeof(*bus), GFP_KERNEL); | ||
| 392 | if (bus == NULL) { | ||
| 393 | ret = -ENOMEM; | ||
| 394 | goto err; | ||
| 395 | } | ||
| 396 | memset(bus, 0, sizeof(*bus)); | ||
| 397 | spin_lock_init(&bus->mii_lock); | ||
| 398 | bus->bus_info = bi; | ||
| 399 | bus->refs = 0; | ||
| 400 | bus->usage_map = 0; | ||
| 401 | |||
| 402 | /* perform initialization */ | ||
| 403 | switch (bi->method) { | ||
| 404 | |||
| 405 | case fsmii_fixed: | ||
| 406 | ret = fs_mii_fixed_init(bus); | ||
| 407 | if (ret != 0) | ||
| 408 | goto err; | ||
| 409 | break; | ||
| 410 | |||
| 411 | case fsmii_bitbang: | ||
| 412 | ret = fs_mii_bitbang_init(bus); | ||
| 413 | if (ret != 0) | ||
| 414 | goto err; | ||
| 415 | break; | ||
| 416 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
| 417 | case fsmii_fec: | ||
| 418 | ret = fs_mii_fec_init(bus); | ||
| 419 | if (ret != 0) | ||
| 420 | goto err; | ||
| 421 | break; | ||
| 422 | #endif | ||
| 423 | default: | ||
| 424 | ret = -EINVAL; | ||
| 425 | goto err; | ||
| 426 | } | ||
| 427 | |||
| 428 | list_add(&bus->list, &fs_mii_bus_list); | ||
| 429 | |||
| 430 | return bus; | ||
| 431 | |||
| 432 | err: | ||
| 433 | kfree(bus); | ||
| 434 | return ERR_PTR(ret); | ||
| 435 | } | ||
| 436 | |||
| 437 | static void destroy_bus(struct fs_enet_mii_bus *bus) | ||
| 438 | { | ||
| 439 | /* remove from bus list */ | ||
| 440 | list_del(&bus->list); | ||
| 441 | |||
| 442 | /* nothing more needed */ | ||
| 443 | kfree(bus); | ||
| 444 | } | ||
| 445 | |||
| 446 | int fs_mii_connect(struct net_device *dev) | ||
| 447 | { | ||
| 448 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 449 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 450 | struct fs_enet_mii_bus *bus = NULL; | ||
| 451 | |||
| 452 | /* check method validity */ | ||
| 453 | switch (fpi->bus_info->method) { | ||
| 454 | case fsmii_fixed: | ||
| 455 | case fsmii_bitbang: | ||
| 456 | break; | ||
| 457 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
| 458 | case fsmii_fec: | ||
| 459 | break; | ||
| 460 | #endif | ||
| 461 | default: | ||
| 462 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 463 | ": %s Unknown MII bus method (%d)!\n", | ||
| 464 | dev->name, fpi->bus_info->method); | ||
| 465 | return -EINVAL; | ||
| 466 | } | ||
| 467 | |||
| 468 | bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id); | ||
| 469 | |||
| 470 | /* if not found create new bus */ | ||
| 471 | if (bus == NULL) { | ||
| 472 | bus = create_bus(fpi->bus_info); | ||
| 473 | if (IS_ERR(bus)) { | ||
| 474 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 475 | ": %s MII bus creation failure!\n", dev->name); | ||
| 476 | return PTR_ERR(bus); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | bus->refs++; | ||
| 481 | |||
| 482 | fep->mii_bus = bus; | ||
| 483 | |||
| 484 | fep->mii_if.dev = dev; | ||
| 485 | fep->mii_if.phy_id_mask = 0x1f; | ||
| 486 | fep->mii_if.reg_num_mask = 0x1f; | ||
| 487 | fep->mii_if.mdio_read = fs_mii_read; | ||
| 488 | fep->mii_if.mdio_write = fs_mii_write; | ||
| 489 | fep->mii_if.force_media = fpi->bus_info->disable_aneg; | ||
| 490 | fep->mii_if.phy_id = phy_id_detect(dev); | ||
| 491 | |||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | void fs_mii_disconnect(struct net_device *dev) | ||
| 496 | { | ||
| 497 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 498 | struct fs_enet_mii_bus *bus = NULL; | ||
| 499 | |||
| 500 | bus = fep->mii_bus; | ||
| 501 | fep->mii_bus = NULL; | ||
| 502 | |||
| 503 | if (--bus->refs <= 0) | ||
| 504 | destroy_bus(bus); | ||
| 505 | } | ||
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index e7ec96c964a9..95022c005f75 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <linux/netdevice.h> | 5 | #include <linux/netdevice.h> |
| 6 | #include <linux/types.h> | 6 | #include <linux/types.h> |
| 7 | #include <linux/list.h> | 7 | #include <linux/list.h> |
| 8 | #include <linux/phy.h> | ||
| 8 | 9 | ||
| 9 | #include <linux/fs_enet_pd.h> | 10 | #include <linux/fs_enet_pd.h> |
| 10 | 11 | ||
| @@ -12,12 +13,30 @@ | |||
| 12 | 13 | ||
| 13 | #ifdef CONFIG_CPM1 | 14 | #ifdef CONFIG_CPM1 |
| 14 | #include <asm/commproc.h> | 15 | #include <asm/commproc.h> |
| 16 | |||
| 17 | struct fec_info { | ||
| 18 | fec_t* fecp; | ||
| 19 | u32 mii_speed; | ||
| 20 | }; | ||
| 15 | #endif | 21 | #endif |
| 16 | 22 | ||
| 17 | #ifdef CONFIG_CPM2 | 23 | #ifdef CONFIG_CPM2 |
| 18 | #include <asm/cpm2.h> | 24 | #include <asm/cpm2.h> |
| 19 | #endif | 25 | #endif |
| 20 | 26 | ||
| 27 | /* This is used to operate with pins. | ||
| 28 | Note that the actual port size may | ||
| 29 | be different; cpm(s) handle it OK */ | ||
| 30 | struct bb_info { | ||
| 31 | u8 mdio_dat_msk; | ||
| 32 | u8 mdio_dir_msk; | ||
| 33 | u8 *mdio_dir; | ||
| 34 | u8 *mdio_dat; | ||
| 35 | u8 mdc_msk; | ||
| 36 | u8 *mdc_dat; | ||
| 37 | int delay; | ||
| 38 | }; | ||
| 39 | |||
| 21 | /* hw driver ops */ | 40 | /* hw driver ops */ |
| 22 | struct fs_ops { | 41 | struct fs_ops { |
| 23 | int (*setup_data)(struct net_device *dev); | 42 | int (*setup_data)(struct net_device *dev); |
| @@ -25,6 +44,7 @@ struct fs_ops { | |||
| 25 | void (*free_bd)(struct net_device *dev); | 44 | void (*free_bd)(struct net_device *dev); |
| 26 | void (*cleanup_data)(struct net_device *dev); | 45 | void (*cleanup_data)(struct net_device *dev); |
| 27 | void (*set_multicast_list)(struct net_device *dev); | 46 | void (*set_multicast_list)(struct net_device *dev); |
| 47 | void (*adjust_link)(struct net_device *dev); | ||
| 28 | void (*restart)(struct net_device *dev); | 48 | void (*restart)(struct net_device *dev); |
| 29 | void (*stop)(struct net_device *dev); | 49 | void (*stop)(struct net_device *dev); |
| 30 | void (*pre_request_irq)(struct net_device *dev, int irq); | 50 | void (*pre_request_irq)(struct net_device *dev, int irq); |
| @@ -100,10 +120,6 @@ struct fs_enet_mii_bus { | |||
| 100 | }; | 120 | }; |
| 101 | }; | 121 | }; |
| 102 | 122 | ||
| 103 | int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus); | ||
| 104 | int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); | ||
| 105 | int fs_mii_fec_init(struct fs_enet_mii_bus *bus); | ||
| 106 | |||
| 107 | struct fs_enet_private { | 123 | struct fs_enet_private { |
| 108 | struct device *dev; /* pointer back to the device (must be initialized first) */ | 124 | struct device *dev; /* pointer back to the device (must be initialized first) */ |
| 109 | spinlock_t lock; /* during all ops except TX pckt processing */ | 125 | spinlock_t lock; /* during all ops except TX pckt processing */ |
| @@ -130,7 +146,8 @@ struct fs_enet_private { | |||
| 130 | struct fs_enet_mii_bus *mii_bus; | 146 | struct fs_enet_mii_bus *mii_bus; |
| 131 | int interrupt; | 147 | int interrupt; |
| 132 | 148 | ||
| 133 | int duplex, speed; /* current settings */ | 149 | struct phy_device *phydev; |
| 150 | int oldduplex, oldspeed, oldlink; /* current settings */ | ||
| 134 | 151 | ||
| 135 | /* event masks */ | 152 | /* event masks */ |
| 136 | u32 ev_napi_rx; /* mask of NAPI rx events */ | 153 | u32 ev_napi_rx; /* mask of NAPI rx events */ |
| @@ -168,15 +185,9 @@ struct fs_enet_private { | |||
| 168 | }; | 185 | }; |
| 169 | 186 | ||
| 170 | /***************************************************************************/ | 187 | /***************************************************************************/ |
| 171 | 188 | int fs_enet_mdio_bb_init(void); | |
| 172 | int fs_mii_read(struct net_device *dev, int phy_id, int location); | 189 | int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); |
| 173 | void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); | 190 | int fs_enet_mdio_fec_init(void); |
| 174 | |||
| 175 | void fs_mii_startup(struct net_device *dev); | ||
| 176 | void fs_mii_shutdown(struct net_device *dev); | ||
| 177 | void fs_mii_ack_int(struct net_device *dev); | ||
| 178 | |||
| 179 | void fs_mii_link_status_change_check(struct net_device *dev, int init_media); | ||
| 180 | 191 | ||
| 181 | void fs_init_bds(struct net_device *dev); | 192 | void fs_init_bds(struct net_device *dev); |
| 182 | void fs_cleanup_bds(struct net_device *dev); | 193 | void fs_cleanup_bds(struct net_device *dev); |
| @@ -194,7 +205,6 @@ int fs_enet_platform_init(void); | |||
| 194 | void fs_enet_platform_cleanup(void); | 205 | void fs_enet_platform_cleanup(void); |
| 195 | 206 | ||
| 196 | /***************************************************************************/ | 207 | /***************************************************************************/ |
| 197 | |||
| 198 | /* buffer descriptor access macros */ | 208 | /* buffer descriptor access macros */ |
| 199 | 209 | ||
| 200 | /* access macros */ | 210 | /* access macros */ |
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 64e20982c1fe..1ff2597b8495 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/bitops.h> | 34 | #include <linux/bitops.h> |
| 35 | #include <linux/fs.h> | 35 | #include <linux/fs.h> |
| 36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
| 37 | #include <linux/phy.h> | ||
| 37 | 38 | ||
| 38 | #include <asm/immap_cpm2.h> | 39 | #include <asm/immap_cpm2.h> |
| 39 | #include <asm/mpc8260.h> | 40 | #include <asm/mpc8260.h> |
| @@ -122,22 +123,32 @@ static int do_pd_setup(struct fs_enet_private *fep) | |||
| 122 | 123 | ||
| 123 | /* Attach the memory for the FCC Parameter RAM */ | 124 | /* Attach the memory for the FCC Parameter RAM */ |
| 124 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); | 125 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); |
| 125 | fep->fcc.ep = (void *)r->start; | 126 | fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1); |
| 126 | |||
| 127 | if (fep->fcc.ep == NULL) | 127 | if (fep->fcc.ep == NULL) |
| 128 | return -EINVAL; | 128 | return -EINVAL; |
| 129 | 129 | ||
| 130 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); | 130 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); |
| 131 | fep->fcc.fccp = (void *)r->start; | 131 | fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1); |
| 132 | |||
| 133 | if (fep->fcc.fccp == NULL) | 132 | if (fep->fcc.fccp == NULL) |
| 134 | return -EINVAL; | 133 | return -EINVAL; |
| 135 | 134 | ||
| 136 | fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; | 135 | if (fep->fpi->fcc_regs_c) { |
| 136 | |||
| 137 | fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; | ||
| 138 | } else { | ||
| 139 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
| 140 | "fcc_regs_c"); | ||
| 141 | fep->fcc.fcccp = (void *)ioremap(r->start, | ||
| 142 | r->end - r->start + 1); | ||
| 143 | } | ||
| 137 | 144 | ||
| 138 | if (fep->fcc.fcccp == NULL) | 145 | if (fep->fcc.fcccp == NULL) |
| 139 | return -EINVAL; | 146 | return -EINVAL; |
| 140 | 147 | ||
| 148 | fep->fcc.mem = (void *)fep->fpi->mem_offset; | ||
| 149 | if (fep->fcc.mem == NULL) | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 141 | return 0; | 152 | return 0; |
| 142 | } | 153 | } |
| 143 | 154 | ||
| @@ -155,8 +166,6 @@ static int setup_data(struct net_device *dev) | |||
| 155 | if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ | 166 | if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ |
| 156 | return -EINVAL; | 167 | return -EINVAL; |
| 157 | 168 | ||
| 158 | fep->fcc.mem = (void *)fpi->mem_offset; | ||
| 159 | |||
| 160 | if (do_pd_setup(fep) != 0) | 169 | if (do_pd_setup(fep) != 0) |
| 161 | return -EINVAL; | 170 | return -EINVAL; |
| 162 | 171 | ||
| @@ -394,7 +403,7 @@ static void restart(struct net_device *dev) | |||
| 394 | 403 | ||
| 395 | /* adjust to speed (for RMII mode) */ | 404 | /* adjust to speed (for RMII mode) */ |
| 396 | if (fpi->use_rmii) { | 405 | if (fpi->use_rmii) { |
| 397 | if (fep->speed == 100) | 406 | if (fep->phydev->speed == 100) |
| 398 | C8(fcccp, fcc_gfemr, 0x20); | 407 | C8(fcccp, fcc_gfemr, 0x20); |
| 399 | else | 408 | else |
| 400 | S8(fcccp, fcc_gfemr, 0x20); | 409 | S8(fcccp, fcc_gfemr, 0x20); |
| @@ -420,7 +429,7 @@ static void restart(struct net_device *dev) | |||
| 420 | S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); | 429 | S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); |
| 421 | 430 | ||
| 422 | /* adjust to duplex mode */ | 431 | /* adjust to duplex mode */ |
| 423 | if (fep->duplex) | 432 | if (fep->phydev->duplex) |
| 424 | S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | 433 | S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); |
| 425 | else | 434 | else |
| 426 | C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | 435 | C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); |
| @@ -486,7 +495,10 @@ static void rx_bd_done(struct net_device *dev) | |||
| 486 | 495 | ||
| 487 | static void tx_kickstart(struct net_device *dev) | 496 | static void tx_kickstart(struct net_device *dev) |
| 488 | { | 497 | { |
| 489 | /* nothing */ | 498 | struct fs_enet_private *fep = netdev_priv(dev); |
| 499 | fcc_t *fccp = fep->fcc.fccp; | ||
| 500 | |||
| 501 | S32(fccp, fcc_ftodr, 0x80); | ||
| 490 | } | 502 | } |
| 491 | 503 | ||
| 492 | static u32 get_int_events(struct net_device *dev) | 504 | static u32 get_int_events(struct net_device *dev) |
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index e09547077529..c2c5fd419bd0 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #endif | 46 | #endif |
| 47 | 47 | ||
| 48 | #include "fs_enet.h" | 48 | #include "fs_enet.h" |
| 49 | #include "fec.h" | ||
| 49 | 50 | ||
| 50 | /*************************************************/ | 51 | /*************************************************/ |
| 51 | 52 | ||
| @@ -75,50 +76,8 @@ | |||
| 75 | /* clear bits */ | 76 | /* clear bits */ |
| 76 | #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) | 77 | #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) |
| 77 | 78 | ||
| 78 | |||
| 79 | /* CRC polynomium used by the FEC for the multicast group filtering */ | ||
| 80 | #define FEC_CRC_POLY 0x04C11DB7 | ||
| 81 | |||
| 82 | #define FEC_MAX_MULTICAST_ADDRS 64 | ||
| 83 | |||
| 84 | /* Interrupt events/masks. | ||
| 85 | */ | ||
| 86 | #define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ | ||
| 87 | #define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ | ||
| 88 | #define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ | ||
| 89 | #define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ | ||
| 90 | #define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ | ||
| 91 | #define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ | ||
| 92 | #define FEC_ENET_RXF 0x02000000U /* Full frame received */ | ||
| 93 | #define FEC_ENET_RXB 0x01000000U /* A buffer was received */ | ||
| 94 | #define FEC_ENET_MII 0x00800000U /* MII interrupt */ | ||
| 95 | #define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ | ||
| 96 | |||
| 97 | #define FEC_ECNTRL_PINMUX 0x00000004 | ||
| 98 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
| 99 | #define FEC_ECNTRL_RESET 0x00000001 | ||
| 100 | |||
| 101 | #define FEC_RCNTRL_BC_REJ 0x00000010 | ||
| 102 | #define FEC_RCNTRL_PROM 0x00000008 | ||
| 103 | #define FEC_RCNTRL_MII_MODE 0x00000004 | ||
| 104 | #define FEC_RCNTRL_DRT 0x00000002 | ||
| 105 | #define FEC_RCNTRL_LOOP 0x00000001 | ||
| 106 | |||
| 107 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
| 108 | #define FEC_TCNTRL_HBC 0x00000002 | ||
| 109 | #define FEC_TCNTRL_GTS 0x00000001 | ||
| 110 | |||
| 111 | |||
| 112 | /* Make MII read/write commands for the FEC. | ||
| 113 | */ | ||
| 114 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
| 115 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
| 116 | #define mk_mii_end 0 | ||
| 117 | |||
| 118 | #define FEC_MII_LOOPS 10000 | ||
| 119 | |||
| 120 | /* | 79 | /* |
| 121 | * Delay to wait for FEC reset command to complete (in us) | 80 | * Delay to wait for FEC reset command to complete (in us) |
| 122 | */ | 81 | */ |
| 123 | #define FEC_RESET_DELAY 50 | 82 | #define FEC_RESET_DELAY 50 |
| 124 | 83 | ||
| @@ -303,13 +262,15 @@ static void restart(struct net_device *dev) | |||
| 303 | int r; | 262 | int r; |
| 304 | u32 addrhi, addrlo; | 263 | u32 addrhi, addrlo; |
| 305 | 264 | ||
| 265 | struct mii_bus* mii = fep->phydev->bus; | ||
| 266 | struct fec_info* fec_inf = mii->priv; | ||
| 267 | |||
| 306 | r = whack_reset(fep->fec.fecp); | 268 | r = whack_reset(fep->fec.fecp); |
| 307 | if (r != 0) | 269 | if (r != 0) |
| 308 | printk(KERN_ERR DRV_MODULE_NAME | 270 | printk(KERN_ERR DRV_MODULE_NAME |
| 309 | ": %s FEC Reset FAILED!\n", dev->name); | 271 | ": %s FEC Reset FAILED!\n", dev->name); |
| 310 | |||
| 311 | /* | 272 | /* |
| 312 | * Set station address. | 273 | * Set station address. |
| 313 | */ | 274 | */ |
| 314 | addrhi = ((u32) dev->dev_addr[0] << 24) | | 275 | addrhi = ((u32) dev->dev_addr[0] << 24) | |
| 315 | ((u32) dev->dev_addr[1] << 16) | | 276 | ((u32) dev->dev_addr[1] << 16) | |
| @@ -350,12 +311,12 @@ static void restart(struct net_device *dev) | |||
| 350 | FW(fecp, fun_code, 0x78000000); | 311 | FW(fecp, fun_code, 0x78000000); |
| 351 | 312 | ||
| 352 | /* | 313 | /* |
| 353 | * Set MII speed. | 314 | * Set MII speed. |
| 354 | */ | 315 | */ |
| 355 | FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); | 316 | FW(fecp, mii_speed, fec_inf->mii_speed); |
| 356 | 317 | ||
| 357 | /* | 318 | /* |
| 358 | * Clear any outstanding interrupt. | 319 | * Clear any outstanding interrupt. |
| 359 | */ | 320 | */ |
| 360 | FW(fecp, ievent, 0xffc0); | 321 | FW(fecp, ievent, 0xffc0); |
| 361 | FW(fecp, ivec, (fep->interrupt / 2) << 29); | 322 | FW(fecp, ivec, (fep->interrupt / 2) << 29); |
| @@ -390,11 +351,12 @@ static void restart(struct net_device *dev) | |||
| 390 | } | 351 | } |
| 391 | #endif | 352 | #endif |
| 392 | 353 | ||
| 354 | |||
| 393 | FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | 355 | FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ |
| 394 | /* | 356 | /* |
| 395 | * adjust to duplex mode | 357 | * adjust to duplex mode |
| 396 | */ | 358 | */ |
| 397 | if (fep->duplex) { | 359 | if (fep->phydev->duplex) { |
| 398 | FC(fecp, r_cntrl, FEC_RCNTRL_DRT); | 360 | FC(fecp, r_cntrl, FEC_RCNTRL_DRT); |
| 399 | FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ | 361 | FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ |
| 400 | } else { | 362 | } else { |
| @@ -418,9 +380,11 @@ static void restart(struct net_device *dev) | |||
| 418 | static void stop(struct net_device *dev) | 380 | static void stop(struct net_device *dev) |
| 419 | { | 381 | { |
| 420 | struct fs_enet_private *fep = netdev_priv(dev); | 382 | struct fs_enet_private *fep = netdev_priv(dev); |
| 383 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 421 | fec_t *fecp = fep->fec.fecp; | 384 | fec_t *fecp = fep->fec.fecp; |
| 422 | struct fs_enet_mii_bus *bus = fep->mii_bus; | 385 | |
| 423 | const struct fs_mii_bus_info *bi = bus->bus_info; | 386 | struct fec_info* feci= fep->phydev->bus->priv; |
| 387 | |||
| 424 | int i; | 388 | int i; |
| 425 | 389 | ||
| 426 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) | 390 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) |
| @@ -444,11 +408,11 @@ static void stop(struct net_device *dev) | |||
| 444 | fs_cleanup_bds(dev); | 408 | fs_cleanup_bds(dev); |
| 445 | 409 | ||
| 446 | /* shut down FEC1? that's where the mii bus is */ | 410 | /* shut down FEC1? that's where the mii bus is */ |
| 447 | if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { | 411 | if (fpi->has_phy) { |
| 448 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | 412 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ |
| 449 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | 413 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); |
| 450 | FW(fecp, ievent, FEC_ENET_MII); | 414 | FW(fecp, ievent, FEC_ENET_MII); |
| 451 | FW(fecp, mii_speed, bus->fec.mii_speed); | 415 | FW(fecp, mii_speed, feci->mii_speed); |
| 452 | } | 416 | } |
| 453 | } | 417 | } |
| 454 | 418 | ||
| @@ -583,73 +547,3 @@ const struct fs_ops fs_fec_ops = { | |||
| 583 | .free_bd = free_bd, | 547 | .free_bd = free_bd, |
| 584 | }; | 548 | }; |
| 585 | 549 | ||
| 586 | /***********************************************************************/ | ||
| 587 | |||
| 588 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | ||
| 589 | { | ||
| 590 | fec_t *fecp = bus->fec.fecp; | ||
| 591 | int i, ret = -1; | ||
| 592 | |||
| 593 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
| 594 | BUG(); | ||
| 595 | |||
| 596 | /* Add PHY address to register command. */ | ||
| 597 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
| 598 | |||
| 599 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
| 600 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
| 601 | break; | ||
| 602 | |||
| 603 | if (i < FEC_MII_LOOPS) { | ||
| 604 | FW(fecp, ievent, FEC_ENET_MII); | ||
| 605 | ret = FR(fecp, mii_data) & 0xffff; | ||
| 606 | } | ||
| 607 | |||
| 608 | return ret; | ||
| 609 | } | ||
| 610 | |||
| 611 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) | ||
| 612 | { | ||
| 613 | fec_t *fecp = bus->fec.fecp; | ||
| 614 | int i; | ||
| 615 | |||
| 616 | /* this must never happen */ | ||
| 617 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
| 618 | BUG(); | ||
| 619 | |||
| 620 | /* Add PHY address to register command. */ | ||
| 621 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); | ||
| 622 | |||
| 623 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
| 624 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
| 625 | break; | ||
| 626 | |||
| 627 | if (i < FEC_MII_LOOPS) | ||
| 628 | FW(fecp, ievent, FEC_ENET_MII); | ||
| 629 | } | ||
| 630 | |||
| 631 | int fs_mii_fec_init(struct fs_enet_mii_bus *bus) | ||
| 632 | { | ||
| 633 | bd_t *bd = (bd_t *)__res; | ||
| 634 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
| 635 | fec_t *fecp; | ||
| 636 | |||
| 637 | if (bi->id != 0) | ||
| 638 | return -1; | ||
| 639 | |||
| 640 | bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; | ||
| 641 | bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) | ||
| 642 | & 0x3F) << 1; | ||
| 643 | |||
| 644 | fecp = bus->fec.fecp; | ||
| 645 | |||
| 646 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
| 647 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
| 648 | FW(fecp, ievent, FEC_ENET_MII); | ||
| 649 | FW(fecp, mii_speed, bus->fec.mii_speed); | ||
| 650 | |||
| 651 | bus->mii_read = mii_read; | ||
| 652 | bus->mii_write = mii_write; | ||
| 653 | |||
| 654 | return 0; | ||
| 655 | } | ||
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index eaa24fab645f..95ec5872c507 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c | |||
| @@ -369,7 +369,7 @@ static void restart(struct net_device *dev) | |||
| 369 | W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); | 369 | W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); |
| 370 | 370 | ||
| 371 | /* Set full duplex mode if needed */ | 371 | /* Set full duplex mode if needed */ |
| 372 | if (fep->duplex) | 372 | if (fep->phydev->duplex) |
| 373 | S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); | 373 | S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); |
| 374 | 374 | ||
| 375 | S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | 375 | S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); |
| @@ -500,6 +500,8 @@ static void tx_restart(struct net_device *dev) | |||
| 500 | scc_cr_cmd(fep, CPM_CR_RESTART_TX); | 500 | scc_cr_cmd(fep, CPM_CR_RESTART_TX); |
| 501 | } | 501 | } |
| 502 | 502 | ||
| 503 | |||
| 504 | |||
| 503 | /*************************************************************************/ | 505 | /*************************************************************************/ |
| 504 | 506 | ||
| 505 | const struct fs_ops fs_scc_ops = { | 507 | const struct fs_ops fs_scc_ops = { |
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 48f9cf83ab6f..0b9b8b5c847c 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/mii.h> | 33 | #include <linux/mii.h> |
| 34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
| 35 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
| 36 | #include <linux/platform_device.h> | ||
| 36 | 37 | ||
| 37 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
| 38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
| @@ -40,129 +41,25 @@ | |||
| 40 | 41 | ||
| 41 | #include "fs_enet.h" | 42 | #include "fs_enet.h" |
| 42 | 43 | ||
| 43 | #ifdef CONFIG_8xx | 44 | static int bitbang_prep_bit(u8 **datp, u8 *mskp, |
| 44 | static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) | 45 | struct fs_mii_bit *mii_bit) |
| 45 | { | 46 | { |
| 46 | immap_t *im = (immap_t *)fs_enet_immap; | 47 | void *dat; |
| 47 | void *dir, *dat, *ppar; | ||
| 48 | int adv; | 48 | int adv; |
| 49 | u8 msk; | 49 | u8 msk; |
| 50 | 50 | ||
| 51 | switch (port) { | 51 | dat = (void*) mii_bit->offset; |
| 52 | case fsiop_porta: | ||
| 53 | dir = &im->im_ioport.iop_padir; | ||
| 54 | dat = &im->im_ioport.iop_padat; | ||
| 55 | ppar = &im->im_ioport.iop_papar; | ||
| 56 | break; | ||
| 57 | |||
| 58 | case fsiop_portb: | ||
| 59 | dir = &im->im_cpm.cp_pbdir; | ||
| 60 | dat = &im->im_cpm.cp_pbdat; | ||
| 61 | ppar = &im->im_cpm.cp_pbpar; | ||
| 62 | break; | ||
| 63 | |||
| 64 | case fsiop_portc: | ||
| 65 | dir = &im->im_ioport.iop_pcdir; | ||
| 66 | dat = &im->im_ioport.iop_pcdat; | ||
| 67 | ppar = &im->im_ioport.iop_pcpar; | ||
| 68 | break; | ||
| 69 | |||
| 70 | case fsiop_portd: | ||
| 71 | dir = &im->im_ioport.iop_pddir; | ||
| 72 | dat = &im->im_ioport.iop_pddat; | ||
| 73 | ppar = &im->im_ioport.iop_pdpar; | ||
| 74 | break; | ||
| 75 | |||
| 76 | case fsiop_porte: | ||
| 77 | dir = &im->im_cpm.cp_pedir; | ||
| 78 | dat = &im->im_cpm.cp_pedat; | ||
| 79 | ppar = &im->im_cpm.cp_pepar; | ||
| 80 | break; | ||
| 81 | |||
| 82 | default: | ||
| 83 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 84 | "Illegal port value %d!\n", port); | ||
| 85 | return -EINVAL; | ||
| 86 | } | ||
| 87 | |||
| 88 | adv = bit >> 3; | ||
| 89 | dir = (char *)dir + adv; | ||
| 90 | dat = (char *)dat + adv; | ||
| 91 | ppar = (char *)ppar + adv; | ||
| 92 | |||
| 93 | msk = 1 << (7 - (bit & 7)); | ||
| 94 | if ((in_8(ppar) & msk) != 0) { | ||
| 95 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 96 | "pin %d on port %d is not general purpose!\n", bit, port); | ||
| 97 | return -EINVAL; | ||
| 98 | } | ||
| 99 | |||
| 100 | *dirp = dir; | ||
| 101 | *datp = dat; | ||
| 102 | *mskp = msk; | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | #endif | ||
| 107 | |||
| 108 | #ifdef CONFIG_8260 | ||
| 109 | static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) | ||
| 110 | { | ||
| 111 | iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; | ||
| 112 | void *dir, *dat, *ppar; | ||
| 113 | int adv; | ||
| 114 | u8 msk; | ||
| 115 | |||
| 116 | switch (port) { | ||
| 117 | case fsiop_porta: | ||
| 118 | dir = &io->iop_pdira; | ||
| 119 | dat = &io->iop_pdata; | ||
| 120 | ppar = &io->iop_ppara; | ||
| 121 | break; | ||
| 122 | |||
| 123 | case fsiop_portb: | ||
| 124 | dir = &io->iop_pdirb; | ||
| 125 | dat = &io->iop_pdatb; | ||
| 126 | ppar = &io->iop_pparb; | ||
| 127 | break; | ||
| 128 | |||
| 129 | case fsiop_portc: | ||
| 130 | dir = &io->iop_pdirc; | ||
| 131 | dat = &io->iop_pdatc; | ||
| 132 | ppar = &io->iop_pparc; | ||
| 133 | break; | ||
| 134 | |||
| 135 | case fsiop_portd: | ||
| 136 | dir = &io->iop_pdird; | ||
| 137 | dat = &io->iop_pdatd; | ||
| 138 | ppar = &io->iop_ppard; | ||
| 139 | break; | ||
| 140 | |||
| 141 | default: | ||
| 142 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 143 | "Illegal port value %d!\n", port); | ||
| 144 | return -EINVAL; | ||
| 145 | } | ||
| 146 | 52 | ||
| 147 | adv = bit >> 3; | 53 | adv = mii_bit->bit >> 3; |
| 148 | dir = (char *)dir + adv; | ||
| 149 | dat = (char *)dat + adv; | 54 | dat = (char *)dat + adv; |
| 150 | ppar = (char *)ppar + adv; | ||
| 151 | 55 | ||
| 152 | msk = 1 << (7 - (bit & 7)); | 56 | msk = 1 << (7 - (mii_bit->bit & 7)); |
| 153 | if ((in_8(ppar) & msk) != 0) { | ||
| 154 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 155 | "pin %d on port %d is not general purpose!\n", bit, port); | ||
| 156 | return -EINVAL; | ||
| 157 | } | ||
| 158 | 57 | ||
| 159 | *dirp = dir; | ||
| 160 | *datp = dat; | 58 | *datp = dat; |
| 161 | *mskp = msk; | 59 | *mskp = msk; |
| 162 | 60 | ||
| 163 | return 0; | 61 | return 0; |
| 164 | } | 62 | } |
| 165 | #endif | ||
| 166 | 63 | ||
| 167 | static inline void bb_set(u8 *p, u8 m) | 64 | static inline void bb_set(u8 *p, u8 m) |
| 168 | { | 65 | { |
| @@ -179,44 +76,44 @@ static inline int bb_read(u8 *p, u8 m) | |||
| 179 | return (in_8(p) & m) != 0; | 76 | return (in_8(p) & m) != 0; |
| 180 | } | 77 | } |
| 181 | 78 | ||
| 182 | static inline void mdio_active(struct fs_enet_mii_bus *bus) | 79 | static inline void mdio_active(struct bb_info *bitbang) |
| 183 | { | 80 | { |
| 184 | bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); | 81 | bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); |
| 185 | } | 82 | } |
| 186 | 83 | ||
| 187 | static inline void mdio_tristate(struct fs_enet_mii_bus *bus) | 84 | static inline void mdio_tristate(struct bb_info *bitbang ) |
| 188 | { | 85 | { |
| 189 | bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); | 86 | bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); |
| 190 | } | 87 | } |
| 191 | 88 | ||
| 192 | static inline int mdio_read(struct fs_enet_mii_bus *bus) | 89 | static inline int mdio_read(struct bb_info *bitbang ) |
| 193 | { | 90 | { |
| 194 | return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | 91 | return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); |
| 195 | } | 92 | } |
| 196 | 93 | ||
| 197 | static inline void mdio(struct fs_enet_mii_bus *bus, int what) | 94 | static inline void mdio(struct bb_info *bitbang , int what) |
| 198 | { | 95 | { |
| 199 | if (what) | 96 | if (what) |
| 200 | bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | 97 | bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); |
| 201 | else | 98 | else |
| 202 | bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | 99 | bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); |
| 203 | } | 100 | } |
| 204 | 101 | ||
| 205 | static inline void mdc(struct fs_enet_mii_bus *bus, int what) | 102 | static inline void mdc(struct bb_info *bitbang , int what) |
| 206 | { | 103 | { |
| 207 | if (what) | 104 | if (what) |
| 208 | bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); | 105 | bb_set(bitbang->mdc_dat, bitbang->mdc_msk); |
| 209 | else | 106 | else |
| 210 | bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); | 107 | bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); |
| 211 | } | 108 | } |
| 212 | 109 | ||
| 213 | static inline void mii_delay(struct fs_enet_mii_bus *bus) | 110 | static inline void mii_delay(struct bb_info *bitbang ) |
| 214 | { | 111 | { |
| 215 | udelay(bus->bus_info->i.bitbang.delay); | 112 | udelay(bitbang->delay); |
| 216 | } | 113 | } |
| 217 | 114 | ||
| 218 | /* Utility to send the preamble, address, and register (common to read and write). */ | 115 | /* Utility to send the preamble, address, and register (common to read and write). */ |
| 219 | static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) | 116 | static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) |
| 220 | { | 117 | { |
| 221 | int j; | 118 | int j; |
| 222 | 119 | ||
| @@ -228,177 +125,284 @@ static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) | |||
| 228 | * but it is safer and will be much more robust. | 125 | * but it is safer and will be much more robust. |
| 229 | */ | 126 | */ |
| 230 | 127 | ||
| 231 | mdio_active(bus); | 128 | mdio_active(bitbang); |
| 232 | mdio(bus, 1); | 129 | mdio(bitbang, 1); |
| 233 | for (j = 0; j < 32; j++) { | 130 | for (j = 0; j < 32; j++) { |
| 234 | mdc(bus, 0); | 131 | mdc(bitbang, 0); |
| 235 | mii_delay(bus); | 132 | mii_delay(bitbang); |
| 236 | mdc(bus, 1); | 133 | mdc(bitbang, 1); |
| 237 | mii_delay(bus); | 134 | mii_delay(bitbang); |
| 238 | } | 135 | } |
| 239 | 136 | ||
| 240 | /* send the start bit (01) and the read opcode (10) or write (10) */ | 137 | /* send the start bit (01) and the read opcode (10) or write (10) */ |
| 241 | mdc(bus, 0); | 138 | mdc(bitbang, 0); |
| 242 | mdio(bus, 0); | 139 | mdio(bitbang, 0); |
| 243 | mii_delay(bus); | 140 | mii_delay(bitbang); |
| 244 | mdc(bus, 1); | 141 | mdc(bitbang, 1); |
| 245 | mii_delay(bus); | 142 | mii_delay(bitbang); |
| 246 | mdc(bus, 0); | 143 | mdc(bitbang, 0); |
| 247 | mdio(bus, 1); | 144 | mdio(bitbang, 1); |
| 248 | mii_delay(bus); | 145 | mii_delay(bitbang); |
| 249 | mdc(bus, 1); | 146 | mdc(bitbang, 1); |
| 250 | mii_delay(bus); | 147 | mii_delay(bitbang); |
| 251 | mdc(bus, 0); | 148 | mdc(bitbang, 0); |
| 252 | mdio(bus, read); | 149 | mdio(bitbang, read); |
| 253 | mii_delay(bus); | 150 | mii_delay(bitbang); |
| 254 | mdc(bus, 1); | 151 | mdc(bitbang, 1); |
| 255 | mii_delay(bus); | 152 | mii_delay(bitbang); |
| 256 | mdc(bus, 0); | 153 | mdc(bitbang, 0); |
| 257 | mdio(bus, !read); | 154 | mdio(bitbang, !read); |
| 258 | mii_delay(bus); | 155 | mii_delay(bitbang); |
| 259 | mdc(bus, 1); | 156 | mdc(bitbang, 1); |
| 260 | mii_delay(bus); | 157 | mii_delay(bitbang); |
| 261 | 158 | ||
| 262 | /* send the PHY address */ | 159 | /* send the PHY address */ |
| 263 | for (j = 0; j < 5; j++) { | 160 | for (j = 0; j < 5; j++) { |
| 264 | mdc(bus, 0); | 161 | mdc(bitbang, 0); |
| 265 | mdio(bus, (addr & 0x10) != 0); | 162 | mdio(bitbang, (addr & 0x10) != 0); |
| 266 | mii_delay(bus); | 163 | mii_delay(bitbang); |
| 267 | mdc(bus, 1); | 164 | mdc(bitbang, 1); |
| 268 | mii_delay(bus); | 165 | mii_delay(bitbang); |
| 269 | addr <<= 1; | 166 | addr <<= 1; |
| 270 | } | 167 | } |
| 271 | 168 | ||
| 272 | /* send the register address */ | 169 | /* send the register address */ |
| 273 | for (j = 0; j < 5; j++) { | 170 | for (j = 0; j < 5; j++) { |
| 274 | mdc(bus, 0); | 171 | mdc(bitbang, 0); |
| 275 | mdio(bus, (reg & 0x10) != 0); | 172 | mdio(bitbang, (reg & 0x10) != 0); |
| 276 | mii_delay(bus); | 173 | mii_delay(bitbang); |
| 277 | mdc(bus, 1); | 174 | mdc(bitbang, 1); |
| 278 | mii_delay(bus); | 175 | mii_delay(bitbang); |
| 279 | reg <<= 1; | 176 | reg <<= 1; |
| 280 | } | 177 | } |
| 281 | } | 178 | } |
| 282 | 179 | ||
| 283 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | 180 | static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) |
| 284 | { | 181 | { |
| 285 | u16 rdreg; | 182 | u16 rdreg; |
| 286 | int ret, j; | 183 | int ret, j; |
| 287 | u8 addr = phy_id & 0xff; | 184 | u8 addr = phy_id & 0xff; |
| 288 | u8 reg = location & 0xff; | 185 | u8 reg = location & 0xff; |
| 186 | struct bb_info* bitbang = bus->priv; | ||
| 289 | 187 | ||
| 290 | bitbang_pre(bus, 1, addr, reg); | 188 | bitbang_pre(bitbang, 1, addr, reg); |
| 291 | 189 | ||
| 292 | /* tri-state our MDIO I/O pin so we can read */ | 190 | /* tri-state our MDIO I/O pin so we can read */ |
| 293 | mdc(bus, 0); | 191 | mdc(bitbang, 0); |
| 294 | mdio_tristate(bus); | 192 | mdio_tristate(bitbang); |
| 295 | mii_delay(bus); | 193 | mii_delay(bitbang); |
| 296 | mdc(bus, 1); | 194 | mdc(bitbang, 1); |
| 297 | mii_delay(bus); | 195 | mii_delay(bitbang); |
| 298 | 196 | ||
| 299 | /* check the turnaround bit: the PHY should be driving it to zero */ | 197 | /* check the turnaround bit: the PHY should be driving it to zero */ |
| 300 | if (mdio_read(bus) != 0) { | 198 | if (mdio_read(bitbang) != 0) { |
| 301 | /* PHY didn't drive TA low */ | 199 | /* PHY didn't drive TA low */ |
| 302 | for (j = 0; j < 32; j++) { | 200 | for (j = 0; j < 32; j++) { |
| 303 | mdc(bus, 0); | 201 | mdc(bitbang, 0); |
| 304 | mii_delay(bus); | 202 | mii_delay(bitbang); |
| 305 | mdc(bus, 1); | 203 | mdc(bitbang, 1); |
| 306 | mii_delay(bus); | 204 | mii_delay(bitbang); |
| 307 | } | 205 | } |
| 308 | ret = -1; | 206 | ret = -1; |
| 309 | goto out; | 207 | goto out; |
| 310 | } | 208 | } |
| 311 | 209 | ||
| 312 | mdc(bus, 0); | 210 | mdc(bitbang, 0); |
| 313 | mii_delay(bus); | 211 | mii_delay(bitbang); |
| 314 | 212 | ||
| 315 | /* read 16 bits of register data, MSB first */ | 213 | /* read 16 bits of register data, MSB first */ |
| 316 | rdreg = 0; | 214 | rdreg = 0; |
| 317 | for (j = 0; j < 16; j++) { | 215 | for (j = 0; j < 16; j++) { |
| 318 | mdc(bus, 1); | 216 | mdc(bitbang, 1); |
| 319 | mii_delay(bus); | 217 | mii_delay(bitbang); |
| 320 | rdreg <<= 1; | 218 | rdreg <<= 1; |
| 321 | rdreg |= mdio_read(bus); | 219 | rdreg |= mdio_read(bitbang); |
| 322 | mdc(bus, 0); | 220 | mdc(bitbang, 0); |
| 323 | mii_delay(bus); | 221 | mii_delay(bitbang); |
| 324 | } | 222 | } |
| 325 | 223 | ||
| 326 | mdc(bus, 1); | 224 | mdc(bitbang, 1); |
| 327 | mii_delay(bus); | 225 | mii_delay(bitbang); |
| 328 | mdc(bus, 0); | 226 | mdc(bitbang, 0); |
| 329 | mii_delay(bus); | 227 | mii_delay(bitbang); |
| 330 | mdc(bus, 1); | 228 | mdc(bitbang, 1); |
| 331 | mii_delay(bus); | 229 | mii_delay(bitbang); |
| 332 | 230 | ||
| 333 | ret = rdreg; | 231 | ret = rdreg; |
| 334 | out: | 232 | out: |
| 335 | return ret; | 233 | return ret; |
| 336 | } | 234 | } |
| 337 | 235 | ||
| 338 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) | 236 | static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) |
| 339 | { | 237 | { |
| 340 | int j; | 238 | int j; |
| 239 | struct bb_info* bitbang = bus->priv; | ||
| 240 | |||
| 341 | u8 addr = phy_id & 0xff; | 241 | u8 addr = phy_id & 0xff; |
| 342 | u8 reg = location & 0xff; | 242 | u8 reg = location & 0xff; |
| 343 | u16 value = val & 0xffff; | 243 | u16 value = val & 0xffff; |
| 344 | 244 | ||
| 345 | bitbang_pre(bus, 0, addr, reg); | 245 | bitbang_pre(bitbang, 0, addr, reg); |
| 346 | 246 | ||
| 347 | /* send the turnaround (10) */ | 247 | /* send the turnaround (10) */ |
| 348 | mdc(bus, 0); | 248 | mdc(bitbang, 0); |
| 349 | mdio(bus, 1); | 249 | mdio(bitbang, 1); |
| 350 | mii_delay(bus); | 250 | mii_delay(bitbang); |
| 351 | mdc(bus, 1); | 251 | mdc(bitbang, 1); |
| 352 | mii_delay(bus); | 252 | mii_delay(bitbang); |
| 353 | mdc(bus, 0); | 253 | mdc(bitbang, 0); |
| 354 | mdio(bus, 0); | 254 | mdio(bitbang, 0); |
| 355 | mii_delay(bus); | 255 | mii_delay(bitbang); |
| 356 | mdc(bus, 1); | 256 | mdc(bitbang, 1); |
| 357 | mii_delay(bus); | 257 | mii_delay(bitbang); |
| 358 | 258 | ||
| 359 | /* write 16 bits of register data, MSB first */ | 259 | /* write 16 bits of register data, MSB first */ |
| 360 | for (j = 0; j < 16; j++) { | 260 | for (j = 0; j < 16; j++) { |
| 361 | mdc(bus, 0); | 261 | mdc(bitbang, 0); |
| 362 | mdio(bus, (value & 0x8000) != 0); | 262 | mdio(bitbang, (value & 0x8000) != 0); |
| 363 | mii_delay(bus); | 263 | mii_delay(bitbang); |
| 364 | mdc(bus, 1); | 264 | mdc(bitbang, 1); |
| 365 | mii_delay(bus); | 265 | mii_delay(bitbang); |
| 366 | value <<= 1; | 266 | value <<= 1; |
| 367 | } | 267 | } |
| 368 | 268 | ||
| 369 | /* | 269 | /* |
| 370 | * Tri-state the MDIO line. | 270 | * Tri-state the MDIO line. |
| 371 | */ | 271 | */ |
| 372 | mdio_tristate(bus); | 272 | mdio_tristate(bitbang); |
| 373 | mdc(bus, 0); | 273 | mdc(bitbang, 0); |
| 374 | mii_delay(bus); | 274 | mii_delay(bitbang); |
| 375 | mdc(bus, 1); | 275 | mdc(bitbang, 1); |
| 376 | mii_delay(bus); | 276 | mii_delay(bitbang); |
| 277 | return 0; | ||
| 377 | } | 278 | } |
| 378 | 279 | ||
| 379 | int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) | 280 | static int fs_enet_mii_bb_reset(struct mii_bus *bus) |
| 281 | { | ||
| 282 | /*nothing here - dunno how to reset it*/ | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) | ||
| 380 | { | 287 | { |
| 381 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
| 382 | int r; | 288 | int r; |
| 383 | 289 | ||
| 384 | r = bitbang_prep_bit(&bus->bitbang.mdio_dir, | 290 | bitbang->delay = fmpi->delay; |
| 385 | &bus->bitbang.mdio_dat, | 291 | |
| 386 | &bus->bitbang.mdio_msk, | 292 | r = bitbang_prep_bit(&bitbang->mdio_dir, |
| 387 | bi->i.bitbang.mdio_port, | 293 | &bitbang->mdio_dir_msk, |
| 388 | bi->i.bitbang.mdio_bit); | 294 | &fmpi->mdio_dir); |
| 389 | if (r != 0) | 295 | if (r != 0) |
| 390 | return r; | 296 | return r; |
| 391 | 297 | ||
| 392 | r = bitbang_prep_bit(&bus->bitbang.mdc_dir, | 298 | r = bitbang_prep_bit(&bitbang->mdio_dat, |
| 393 | &bus->bitbang.mdc_dat, | 299 | &bitbang->mdio_dat_msk, |
| 394 | &bus->bitbang.mdc_msk, | 300 | &fmpi->mdio_dat); |
| 395 | bi->i.bitbang.mdc_port, | ||
| 396 | bi->i.bitbang.mdc_bit); | ||
| 397 | if (r != 0) | 301 | if (r != 0) |
| 398 | return r; | 302 | return r; |
| 399 | 303 | ||
| 400 | bus->mii_read = mii_read; | 304 | r = bitbang_prep_bit(&bitbang->mdc_dat, |
| 401 | bus->mii_write = mii_write; | 305 | &bitbang->mdc_msk, |
| 306 | &fmpi->mdc_dat); | ||
| 307 | if (r != 0) | ||
| 308 | return r; | ||
| 402 | 309 | ||
| 403 | return 0; | 310 | return 0; |
| 404 | } | 311 | } |
| 312 | |||
| 313 | |||
| 314 | static int __devinit fs_enet_mdio_probe(struct device *dev) | ||
| 315 | { | ||
| 316 | struct platform_device *pdev = to_platform_device(dev); | ||
| 317 | struct fs_mii_bb_platform_info *pdata; | ||
| 318 | struct mii_bus *new_bus; | ||
| 319 | struct bb_info *bitbang; | ||
| 320 | int err = 0; | ||
| 321 | |||
| 322 | if (NULL == dev) | ||
| 323 | return -EINVAL; | ||
| 324 | |||
| 325 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | ||
| 326 | |||
| 327 | if (NULL == new_bus) | ||
| 328 | return -ENOMEM; | ||
| 329 | |||
| 330 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); | ||
| 331 | |||
| 332 | if (NULL == bitbang) | ||
| 333 | return -ENOMEM; | ||
| 334 | |||
| 335 | new_bus->name = "BB MII Bus", | ||
| 336 | new_bus->read = &fs_enet_mii_bb_read, | ||
| 337 | new_bus->write = &fs_enet_mii_bb_write, | ||
| 338 | new_bus->reset = &fs_enet_mii_bb_reset, | ||
| 339 | new_bus->id = pdev->id; | ||
| 340 | |||
| 341 | new_bus->phy_mask = ~0x9; | ||
| 342 | pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data; | ||
| 343 | |||
| 344 | if (NULL == pdata) { | ||
| 345 | printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); | ||
| 346 | return -ENODEV; | ||
| 347 | } | ||
| 348 | |||
| 349 | /*set up workspace*/ | ||
| 350 | fs_mii_bitbang_init(bitbang, pdata); | ||
| 351 | |||
| 352 | new_bus->priv = bitbang; | ||
| 353 | |||
| 354 | new_bus->irq = pdata->irq; | ||
| 355 | |||
| 356 | new_bus->dev = dev; | ||
| 357 | dev_set_drvdata(dev, new_bus); | ||
| 358 | |||
| 359 | err = mdiobus_register(new_bus); | ||
| 360 | |||
| 361 | if (0 != err) { | ||
| 362 | printk (KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
| 363 | new_bus->name); | ||
| 364 | goto bus_register_fail; | ||
| 365 | } | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | |||
| 369 | bus_register_fail: | ||
| 370 | kfree(bitbang); | ||
| 371 | kfree(new_bus); | ||
| 372 | |||
| 373 | return err; | ||
| 374 | } | ||
| 375 | |||
| 376 | |||
| 377 | static int fs_enet_mdio_remove(struct device *dev) | ||
| 378 | { | ||
| 379 | struct mii_bus *bus = dev_get_drvdata(dev); | ||
| 380 | |||
| 381 | mdiobus_unregister(bus); | ||
| 382 | |||
| 383 | dev_set_drvdata(dev, NULL); | ||
| 384 | |||
| 385 | iounmap((void *) (&bus->priv)); | ||
| 386 | bus->priv = NULL; | ||
| 387 | kfree(bus); | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static struct device_driver fs_enet_bb_mdio_driver = { | ||
| 393 | .name = "fsl-bb-mdio", | ||
| 394 | .bus = &platform_bus_type, | ||
| 395 | .probe = fs_enet_mdio_probe, | ||
| 396 | .remove = fs_enet_mdio_remove, | ||
| 397 | }; | ||
| 398 | |||
| 399 | int fs_enet_mdio_bb_init(void) | ||
| 400 | { | ||
| 401 | return driver_register(&fs_enet_bb_mdio_driver); | ||
| 402 | } | ||
| 403 | |||
| 404 | void fs_enet_mdio_bb_exit(void) | ||
| 405 | { | ||
| 406 | driver_unregister(&fs_enet_bb_mdio_driver); | ||
| 407 | } | ||
| 408 | |||
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c new file mode 100644 index 000000000000..1328e10caa35 --- /dev/null +++ b/drivers/net/fs_enet/mii-fec.c | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | /* | ||
| 2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | |||
| 16 | #include <linux/config.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/types.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/sched.h> | ||
| 21 | #include <linux/string.h> | ||
| 22 | #include <linux/ptrace.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/ioport.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/pci.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/delay.h> | ||
| 30 | #include <linux/netdevice.h> | ||
| 31 | #include <linux/etherdevice.h> | ||
| 32 | #include <linux/skbuff.h> | ||
| 33 | #include <linux/spinlock.h> | ||
| 34 | #include <linux/mii.h> | ||
| 35 | #include <linux/ethtool.h> | ||
| 36 | #include <linux/bitops.h> | ||
| 37 | #include <linux/platform_device.h> | ||
| 38 | |||
| 39 | #include <asm/pgtable.h> | ||
| 40 | #include <asm/irq.h> | ||
| 41 | #include <asm/uaccess.h> | ||
| 42 | |||
| 43 | #include "fs_enet.h" | ||
| 44 | #include "fec.h" | ||
| 45 | |||
| 46 | /* Make MII read/write commands for the FEC. | ||
| 47 | */ | ||
| 48 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
| 49 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
| 50 | #define mk_mii_end 0 | ||
| 51 | |||
| 52 | #define FEC_MII_LOOPS 10000 | ||
| 53 | |||
| 54 | static int match_has_phy (struct device *dev, void* data) | ||
| 55 | { | ||
| 56 | struct platform_device* pdev = container_of(dev, struct platform_device, dev); | ||
| 57 | struct fs_platform_info* fpi; | ||
| 58 | if(strcmp(pdev->name, (char*)data)) | ||
| 59 | { | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | fpi = pdev->dev.platform_data; | ||
| 64 | if((fpi)&&(fpi->has_phy)) | ||
| 65 | return 1; | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi) | ||
| 70 | { | ||
| 71 | struct resource *r; | ||
| 72 | fec_t *fecp; | ||
| 73 | char* name = "fsl-cpm-fec"; | ||
| 74 | |||
| 75 | /* we need fec in order to be useful */ | ||
| 76 | struct platform_device *fec_pdev = | ||
| 77 | container_of(bus_find_device(&platform_bus_type, NULL, name, match_has_phy), | ||
| 78 | struct platform_device, dev); | ||
| 79 | |||
| 80 | if(fec_pdev == NULL) { | ||
| 81 | printk(KERN_ERR"Unable to find PHY for %s", name); | ||
| 82 | return -ENODEV; | ||
| 83 | } | ||
| 84 | |||
| 85 | r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs"); | ||
| 86 | |||
| 87 | fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t)); | ||
| 88 | fec->mii_speed = fmpi->mii_speed; | ||
| 89 | |||
| 90 | setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
| 91 | setbits32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
| 92 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
| 93 | out_be32(&fecp->fec_mii_speed, fec->mii_speed); | ||
| 94 | |||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) | ||
| 99 | { | ||
| 100 | struct fec_info* fec = bus->priv; | ||
| 101 | fec_t *fecp = fec->fecp; | ||
| 102 | int i, ret = -1; | ||
| 103 | |||
| 104 | if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
| 105 | BUG(); | ||
| 106 | |||
| 107 | /* Add PHY address to register command. */ | ||
| 108 | out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
| 109 | |||
| 110 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
| 111 | if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) | ||
| 112 | break; | ||
| 113 | |||
| 114 | if (i < FEC_MII_LOOPS) { | ||
| 115 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
| 116 | ret = in_be32(&fecp->fec_mii_data) & 0xffff; | ||
| 117 | } | ||
| 118 | |||
| 119 | return ret; | ||
| 120 | |||
| 121 | } | ||
| 122 | |||
| 123 | static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) | ||
| 124 | { | ||
| 125 | struct fec_info* fec = bus->priv; | ||
| 126 | fec_t *fecp = fec->fecp; | ||
| 127 | int i; | ||
| 128 | |||
| 129 | /* this must never happen */ | ||
| 130 | if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
| 131 | BUG(); | ||
| 132 | |||
| 133 | /* Add PHY address to register command. */ | ||
| 134 | out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); | ||
| 135 | |||
| 136 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
| 137 | if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) | ||
| 138 | break; | ||
| 139 | |||
| 140 | if (i < FEC_MII_LOOPS) | ||
| 141 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | |||
| 145 | } | ||
| 146 | |||
| 147 | static int fs_enet_fec_mii_reset(struct mii_bus *bus) | ||
| 148 | { | ||
| 149 | /* nothing here - for now */ | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int __devinit fs_enet_fec_mdio_probe(struct device *dev) | ||
| 154 | { | ||
| 155 | struct platform_device *pdev = to_platform_device(dev); | ||
| 156 | struct fs_mii_fec_platform_info *pdata; | ||
| 157 | struct mii_bus *new_bus; | ||
| 158 | struct fec_info *fec; | ||
| 159 | int err = 0; | ||
| 160 | if (NULL == dev) | ||
| 161 | return -EINVAL; | ||
| 162 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | ||
| 163 | |||
| 164 | if (NULL == new_bus) | ||
| 165 | return -ENOMEM; | ||
| 166 | |||
| 167 | fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); | ||
| 168 | |||
| 169 | if (NULL == fec) | ||
| 170 | return -ENOMEM; | ||
| 171 | |||
| 172 | new_bus->name = "FEC MII Bus", | ||
| 173 | new_bus->read = &fs_enet_fec_mii_read, | ||
| 174 | new_bus->write = &fs_enet_fec_mii_write, | ||
| 175 | new_bus->reset = &fs_enet_fec_mii_reset, | ||
| 176 | new_bus->id = pdev->id; | ||
| 177 | |||
| 178 | pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data; | ||
| 179 | |||
| 180 | if (NULL == pdata) { | ||
| 181 | printk(KERN_ERR "fs_enet FEC mdio %d: Missing platform data!\n", pdev->id); | ||
| 182 | return -ENODEV; | ||
| 183 | } | ||
| 184 | |||
| 185 | /*set up workspace*/ | ||
| 186 | |||
| 187 | fs_mii_fec_init(fec, pdata); | ||
| 188 | new_bus->priv = fec; | ||
| 189 | |||
| 190 | new_bus->irq = pdata->irq; | ||
| 191 | |||
| 192 | new_bus->dev = dev; | ||
| 193 | dev_set_drvdata(dev, new_bus); | ||
| 194 | |||
| 195 | err = mdiobus_register(new_bus); | ||
| 196 | |||
| 197 | if (0 != err) { | ||
| 198 | printk (KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
| 199 | new_bus->name); | ||
| 200 | goto bus_register_fail; | ||
| 201 | } | ||
| 202 | |||
| 203 | return 0; | ||
| 204 | |||
| 205 | bus_register_fail: | ||
| 206 | kfree(new_bus); | ||
| 207 | |||
| 208 | return err; | ||
| 209 | } | ||
| 210 | |||
| 211 | |||
| 212 | static int fs_enet_fec_mdio_remove(struct device *dev) | ||
| 213 | { | ||
| 214 | struct mii_bus *bus = dev_get_drvdata(dev); | ||
| 215 | |||
| 216 | mdiobus_unregister(bus); | ||
| 217 | |||
| 218 | dev_set_drvdata(dev, NULL); | ||
| 219 | kfree(bus->priv); | ||
| 220 | |||
| 221 | bus->priv = NULL; | ||
| 222 | kfree(bus); | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | static struct device_driver fs_enet_fec_mdio_driver = { | ||
| 228 | .name = "fsl-cpm-fec-mdio", | ||
| 229 | .bus = &platform_bus_type, | ||
| 230 | .probe = fs_enet_fec_mdio_probe, | ||
| 231 | .remove = fs_enet_fec_mdio_remove, | ||
| 232 | }; | ||
| 233 | |||
| 234 | int fs_enet_mdio_fec_init(void) | ||
| 235 | { | ||
| 236 | return driver_register(&fs_enet_fec_mdio_driver); | ||
| 237 | } | ||
| 238 | |||
| 239 | void fs_enet_mdio_fec_exit(void) | ||
| 240 | { | ||
| 241 | driver_unregister(&fs_enet_fec_mdio_driver); | ||
| 242 | } | ||
| 243 | |||
diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c deleted file mode 100644 index ae4a9c3bb393..000000000000 --- a/drivers/net/fs_enet/mii-fixed.c +++ /dev/null | |||
| @@ -1,91 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/sched.h> | ||
| 20 | #include <linux/string.h> | ||
| 21 | #include <linux/ptrace.h> | ||
| 22 | #include <linux/errno.h> | ||
| 23 | #include <linux/ioport.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/interrupt.h> | ||
| 26 | #include <linux/pci.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/delay.h> | ||
| 29 | #include <linux/netdevice.h> | ||
| 30 | #include <linux/etherdevice.h> | ||
| 31 | #include <linux/skbuff.h> | ||
| 32 | #include <linux/spinlock.h> | ||
| 33 | #include <linux/mii.h> | ||
| 34 | #include <linux/ethtool.h> | ||
| 35 | #include <linux/bitops.h> | ||
| 36 | |||
| 37 | #include <asm/pgtable.h> | ||
| 38 | #include <asm/irq.h> | ||
| 39 | #include <asm/uaccess.h> | ||
| 40 | |||
| 41 | #include "fs_enet.h" | ||
| 42 | |||
| 43 | static const u16 mii_regs[7] = { | ||
| 44 | 0x3100, | ||
| 45 | 0x786d, | ||
| 46 | 0x0fff, | ||
| 47 | 0x0fff, | ||
| 48 | 0x01e1, | ||
| 49 | 0x45e1, | ||
| 50 | 0x0003, | ||
| 51 | }; | ||
| 52 | |||
| 53 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | ||
| 54 | { | ||
| 55 | int ret = 0; | ||
| 56 | |||
| 57 | if ((unsigned int)location >= ARRAY_SIZE(mii_regs)) | ||
| 58 | return -1; | ||
| 59 | |||
| 60 | if (location != 5) | ||
| 61 | ret = mii_regs[location]; | ||
| 62 | else | ||
| 63 | ret = bus->fixed.lpa; | ||
| 64 | |||
| 65 | return ret; | ||
| 66 | } | ||
| 67 | |||
| 68 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) | ||
| 69 | { | ||
| 70 | /* do nothing */ | ||
| 71 | } | ||
| 72 | |||
| 73 | int fs_mii_fixed_init(struct fs_enet_mii_bus *bus) | ||
| 74 | { | ||
| 75 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
| 76 | |||
| 77 | bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */ | ||
| 78 | |||
| 79 | /* if speed is fixed at 10Mb, remove 100Mb modes */ | ||
| 80 | if (bi->i.fixed.speed == 10) | ||
| 81 | bus->fixed.lpa &= ~LPA_100; | ||
| 82 | |||
| 83 | /* if duplex is half, remove full duplex modes */ | ||
| 84 | if (bi->i.fixed.duplex == 0) | ||
| 85 | bus->fixed.lpa &= ~LPA_DUPLEX; | ||
| 86 | |||
| 87 | bus->mii_read = mii_read; | ||
| 88 | bus->mii_write = mii_write; | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
