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 | } | ||