diff options
Diffstat (limited to 'drivers/net/fec_mpc52xx.c')
-rw-r--r-- | drivers/net/fec_mpc52xx.c | 180 |
1 files changed, 53 insertions, 127 deletions
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 8bbe7f617994..7d443405bbe2 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/hardirq.h> | 25 | #include <linux/hardirq.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/of_device.h> | 27 | #include <linux/of_device.h> |
28 | #include <linux/of_mdio.h> | ||
28 | #include <linux/of_platform.h> | 29 | #include <linux/of_platform.h> |
29 | 30 | ||
30 | #include <linux/netdevice.h> | 31 | #include <linux/netdevice.h> |
@@ -43,11 +44,9 @@ | |||
43 | 44 | ||
44 | #define DRIVER_NAME "mpc52xx-fec" | 45 | #define DRIVER_NAME "mpc52xx-fec" |
45 | 46 | ||
46 | #define FEC5200_PHYADDR_NONE (-1) | ||
47 | #define FEC5200_PHYADDR_7WIRE (-2) | ||
48 | |||
49 | /* Private driver data structure */ | 47 | /* Private driver data structure */ |
50 | struct mpc52xx_fec_priv { | 48 | struct mpc52xx_fec_priv { |
49 | struct net_device *ndev; | ||
51 | int duplex; | 50 | int duplex; |
52 | int speed; | 51 | int speed; |
53 | int r_irq; | 52 | int r_irq; |
@@ -59,10 +58,11 @@ struct mpc52xx_fec_priv { | |||
59 | int msg_enable; | 58 | int msg_enable; |
60 | 59 | ||
61 | /* MDIO link details */ | 60 | /* MDIO link details */ |
62 | int phy_addr; | 61 | unsigned int mdio_speed; |
63 | unsigned int phy_speed; | 62 | struct device_node *phy_node; |
64 | struct phy_device *phydev; | 63 | struct phy_device *phydev; |
65 | enum phy_state link; | 64 | enum phy_state link; |
65 | int seven_wire_mode; | ||
66 | }; | 66 | }; |
67 | 67 | ||
68 | 68 | ||
@@ -211,85 +211,25 @@ static void mpc52xx_fec_adjust_link(struct net_device *dev) | |||
211 | phy_print_status(phydev); | 211 | phy_print_status(phydev); |
212 | } | 212 | } |
213 | 213 | ||
214 | static int mpc52xx_fec_init_phy(struct net_device *dev) | ||
215 | { | ||
216 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
217 | struct phy_device *phydev; | ||
218 | char phy_id[BUS_ID_SIZE]; | ||
219 | |||
220 | snprintf(phy_id, sizeof(phy_id), "%x:%02x", | ||
221 | (unsigned int)dev->base_addr, priv->phy_addr); | ||
222 | |||
223 | priv->link = PHY_DOWN; | ||
224 | priv->speed = 0; | ||
225 | priv->duplex = -1; | ||
226 | |||
227 | phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII); | ||
228 | if (IS_ERR(phydev)) { | ||
229 | dev_err(&dev->dev, "phy_connect failed\n"); | ||
230 | return PTR_ERR(phydev); | ||
231 | } | ||
232 | dev_info(&dev->dev, "attached phy %i to driver %s\n", | ||
233 | phydev->addr, phydev->drv->name); | ||
234 | |||
235 | priv->phydev = phydev; | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int mpc52xx_fec_phy_start(struct net_device *dev) | ||
241 | { | ||
242 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
243 | int err; | ||
244 | |||
245 | if (priv->phy_addr < 0) | ||
246 | return 0; | ||
247 | |||
248 | err = mpc52xx_fec_init_phy(dev); | ||
249 | if (err) { | ||
250 | dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n"); | ||
251 | return err; | ||
252 | } | ||
253 | |||
254 | /* reset phy - this also wakes it from PDOWN */ | ||
255 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); | ||
256 | phy_start(priv->phydev); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static void mpc52xx_fec_phy_stop(struct net_device *dev) | ||
262 | { | ||
263 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
264 | |||
265 | if (!priv->phydev) | ||
266 | return; | ||
267 | |||
268 | phy_disconnect(priv->phydev); | ||
269 | /* power down phy */ | ||
270 | phy_stop(priv->phydev); | ||
271 | phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN); | ||
272 | } | ||
273 | |||
274 | static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv) | ||
275 | { | ||
276 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
277 | |||
278 | if (priv->phydev) | ||
279 | return; | ||
280 | |||
281 | out_be32(&fec->mii_speed, priv->phy_speed); | ||
282 | } | ||
283 | |||
284 | static int mpc52xx_fec_open(struct net_device *dev) | 214 | static int mpc52xx_fec_open(struct net_device *dev) |
285 | { | 215 | { |
286 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | 216 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); |
287 | int err = -EBUSY; | 217 | int err = -EBUSY; |
288 | 218 | ||
219 | if (priv->phy_node) { | ||
220 | priv->phydev = of_phy_connect(priv->ndev, priv->phy_node, | ||
221 | mpc52xx_fec_adjust_link, 0, 0); | ||
222 | if (!priv->phydev) { | ||
223 | dev_err(&dev->dev, "of_phy_connect failed\n"); | ||
224 | return -ENODEV; | ||
225 | } | ||
226 | phy_start(priv->phydev); | ||
227 | } | ||
228 | |||
289 | if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, | 229 | if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, |
290 | DRIVER_NAME "_ctrl", dev)) { | 230 | DRIVER_NAME "_ctrl", dev)) { |
291 | dev_err(&dev->dev, "ctrl interrupt request failed\n"); | 231 | dev_err(&dev->dev, "ctrl interrupt request failed\n"); |
292 | goto out; | 232 | goto free_phy; |
293 | } | 233 | } |
294 | if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, | 234 | if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, |
295 | DRIVER_NAME "_rx", dev)) { | 235 | DRIVER_NAME "_rx", dev)) { |
@@ -311,10 +251,6 @@ static int mpc52xx_fec_open(struct net_device *dev) | |||
311 | goto free_irqs; | 251 | goto free_irqs; |
312 | } | 252 | } |
313 | 253 | ||
314 | err = mpc52xx_fec_phy_start(dev); | ||
315 | if (err) | ||
316 | goto free_skbs; | ||
317 | |||
318 | bcom_enable(priv->rx_dmatsk); | 254 | bcom_enable(priv->rx_dmatsk); |
319 | bcom_enable(priv->tx_dmatsk); | 255 | bcom_enable(priv->tx_dmatsk); |
320 | 256 | ||
@@ -324,16 +260,18 @@ static int mpc52xx_fec_open(struct net_device *dev) | |||
324 | 260 | ||
325 | return 0; | 261 | return 0; |
326 | 262 | ||
327 | free_skbs: | ||
328 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
329 | |||
330 | free_irqs: | 263 | free_irqs: |
331 | free_irq(priv->t_irq, dev); | 264 | free_irq(priv->t_irq, dev); |
332 | free_2irqs: | 265 | free_2irqs: |
333 | free_irq(priv->r_irq, dev); | 266 | free_irq(priv->r_irq, dev); |
334 | free_ctrl_irq: | 267 | free_ctrl_irq: |
335 | free_irq(dev->irq, dev); | 268 | free_irq(dev->irq, dev); |
336 | out: | 269 | free_phy: |
270 | if (priv->phydev) { | ||
271 | phy_stop(priv->phydev); | ||
272 | phy_disconnect(priv->phydev); | ||
273 | priv->phydev = NULL; | ||
274 | } | ||
337 | 275 | ||
338 | return err; | 276 | return err; |
339 | } | 277 | } |
@@ -352,7 +290,12 @@ static int mpc52xx_fec_close(struct net_device *dev) | |||
352 | free_irq(priv->r_irq, dev); | 290 | free_irq(priv->r_irq, dev); |
353 | free_irq(priv->t_irq, dev); | 291 | free_irq(priv->t_irq, dev); |
354 | 292 | ||
355 | mpc52xx_fec_phy_stop(dev); | 293 | if (priv->phydev) { |
294 | /* power down phy */ | ||
295 | phy_stop(priv->phydev); | ||
296 | phy_disconnect(priv->phydev); | ||
297 | priv->phydev = NULL; | ||
298 | } | ||
356 | 299 | ||
357 | return 0; | 300 | return 0; |
358 | } | 301 | } |
@@ -696,7 +639,7 @@ static void mpc52xx_fec_hw_init(struct net_device *dev) | |||
696 | /* set phy speed. | 639 | /* set phy speed. |
697 | * this can't be done in phy driver, since it needs to be called | 640 | * this can't be done in phy driver, since it needs to be called |
698 | * before fec stuff (even on resume) */ | 641 | * before fec stuff (even on resume) */ |
699 | mpc52xx_fec_phy_hw_init(priv); | 642 | out_be32(&fec->mii_speed, priv->mdio_speed); |
700 | } | 643 | } |
701 | 644 | ||
702 | /** | 645 | /** |
@@ -732,7 +675,7 @@ static void mpc52xx_fec_start(struct net_device *dev) | |||
732 | rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ | 675 | rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ |
733 | rcntrl |= FEC_RCNTRL_FCE; | 676 | rcntrl |= FEC_RCNTRL_FCE; |
734 | 677 | ||
735 | if (priv->phy_addr != FEC5200_PHYADDR_7WIRE) | 678 | if (!priv->seven_wire_mode) |
736 | rcntrl |= FEC_RCNTRL_MII_MODE; | 679 | rcntrl |= FEC_RCNTRL_MII_MODE; |
737 | 680 | ||
738 | if (priv->duplex == DUPLEX_FULL) | 681 | if (priv->duplex == DUPLEX_FULL) |
@@ -798,8 +741,6 @@ static void mpc52xx_fec_stop(struct net_device *dev) | |||
798 | 741 | ||
799 | /* Stop FEC */ | 742 | /* Stop FEC */ |
800 | out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN); | 743 | out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN); |
801 | |||
802 | return; | ||
803 | } | 744 | } |
804 | 745 | ||
805 | /* reset fec and bestcomm tasks */ | 746 | /* reset fec and bestcomm tasks */ |
@@ -817,9 +758,11 @@ static void mpc52xx_fec_reset(struct net_device *dev) | |||
817 | 758 | ||
818 | mpc52xx_fec_hw_init(dev); | 759 | mpc52xx_fec_hw_init(dev); |
819 | 760 | ||
820 | phy_stop(priv->phydev); | 761 | if (priv->phydev) { |
821 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); | 762 | phy_stop(priv->phydev); |
822 | phy_start(priv->phydev); | 763 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); |
764 | phy_start(priv->phydev); | ||
765 | } | ||
823 | 766 | ||
824 | bcom_fec_rx_reset(priv->rx_dmatsk); | 767 | bcom_fec_rx_reset(priv->rx_dmatsk); |
825 | bcom_fec_tx_reset(priv->tx_dmatsk); | 768 | bcom_fec_tx_reset(priv->tx_dmatsk); |
@@ -919,8 +862,6 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | |||
919 | struct net_device *ndev; | 862 | struct net_device *ndev; |
920 | struct mpc52xx_fec_priv *priv = NULL; | 863 | struct mpc52xx_fec_priv *priv = NULL; |
921 | struct resource mem; | 864 | struct resource mem; |
922 | struct device_node *phy_node; | ||
923 | const phandle *phy_handle; | ||
924 | const u32 *prop; | 865 | const u32 *prop; |
925 | int prop_size; | 866 | int prop_size; |
926 | 867 | ||
@@ -933,6 +874,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | |||
933 | return -ENOMEM; | 874 | return -ENOMEM; |
934 | 875 | ||
935 | priv = netdev_priv(ndev); | 876 | priv = netdev_priv(ndev); |
877 | priv->ndev = ndev; | ||
936 | 878 | ||
937 | /* Reserve FEC control zone */ | 879 | /* Reserve FEC control zone */ |
938 | rv = of_address_to_resource(op->node, 0, &mem); | 880 | rv = of_address_to_resource(op->node, 0, &mem); |
@@ -956,6 +898,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | |||
956 | ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; | 898 | ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; |
957 | ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; | 899 | ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; |
958 | ndev->base_addr = mem.start; | 900 | ndev->base_addr = mem.start; |
901 | SET_NETDEV_DEV(ndev, &op->dev); | ||
959 | 902 | ||
960 | spin_lock_init(&priv->lock); | 903 | spin_lock_init(&priv->lock); |
961 | 904 | ||
@@ -1003,14 +946,9 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | |||
1003 | */ | 946 | */ |
1004 | 947 | ||
1005 | /* Start with safe defaults for link connection */ | 948 | /* Start with safe defaults for link connection */ |
1006 | priv->phy_addr = FEC5200_PHYADDR_NONE; | ||
1007 | priv->speed = 100; | 949 | priv->speed = 100; |
1008 | priv->duplex = DUPLEX_HALF; | 950 | priv->duplex = DUPLEX_HALF; |
1009 | priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; | 951 | priv->mdio_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; |
1010 | |||
1011 | /* the 7-wire property means don't use MII mode */ | ||
1012 | if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) | ||
1013 | priv->phy_addr = FEC5200_PHYADDR_7WIRE; | ||
1014 | 952 | ||
1015 | /* The current speed preconfigures the speed of the MII link */ | 953 | /* The current speed preconfigures the speed of the MII link */ |
1016 | prop = of_get_property(op->node, "current-speed", &prop_size); | 954 | prop = of_get_property(op->node, "current-speed", &prop_size); |
@@ -1019,43 +957,23 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | |||
1019 | priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF; | 957 | priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF; |
1020 | } | 958 | } |
1021 | 959 | ||
1022 | /* If there is a phy handle, setup link to that phy */ | 960 | /* If there is a phy handle, then get the PHY node */ |
1023 | phy_handle = of_get_property(op->node, "phy-handle", &prop_size); | 961 | priv->phy_node = of_parse_phandle(op->node, "phy-handle", 0); |
1024 | if (phy_handle && (prop_size >= sizeof(phandle))) { | 962 | |
1025 | phy_node = of_find_node_by_phandle(*phy_handle); | 963 | /* the 7-wire property means don't use MII mode */ |
1026 | prop = of_get_property(phy_node, "reg", &prop_size); | 964 | if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) { |
1027 | if (prop && (prop_size >= sizeof(u32))) | 965 | priv->seven_wire_mode = 1; |
1028 | if ((*prop >= 0) && (*prop < PHY_MAX_ADDR)) | 966 | dev_info(&ndev->dev, "using 7-wire PHY mode\n"); |
1029 | priv->phy_addr = *prop; | ||
1030 | of_node_put(phy_node); | ||
1031 | } | 967 | } |
1032 | 968 | ||
1033 | /* Hardware init */ | 969 | /* Hardware init */ |
1034 | mpc52xx_fec_hw_init(ndev); | 970 | mpc52xx_fec_hw_init(ndev); |
1035 | |||
1036 | mpc52xx_fec_reset_stats(ndev); | 971 | mpc52xx_fec_reset_stats(ndev); |
1037 | 972 | ||
1038 | SET_NETDEV_DEV(ndev, &op->dev); | ||
1039 | |||
1040 | /* Register the new network device */ | ||
1041 | rv = register_netdev(ndev); | 973 | rv = register_netdev(ndev); |
1042 | if (rv < 0) | 974 | if (rv < 0) |
1043 | goto probe_error; | 975 | goto probe_error; |
1044 | 976 | ||
1045 | /* Now report the link setup */ | ||
1046 | switch (priv->phy_addr) { | ||
1047 | case FEC5200_PHYADDR_NONE: | ||
1048 | dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n", | ||
1049 | priv->speed, priv->duplex ? 'F' : 'H'); | ||
1050 | break; | ||
1051 | case FEC5200_PHYADDR_7WIRE: | ||
1052 | dev_info(&ndev->dev, "using 7-wire PHY mode\n"); | ||
1053 | break; | ||
1054 | default: | ||
1055 | dev_info(&ndev->dev, "Using PHY at MDIO address %i\n", | ||
1056 | priv->phy_addr); | ||
1057 | } | ||
1058 | |||
1059 | /* We're done ! */ | 977 | /* We're done ! */ |
1060 | dev_set_drvdata(&op->dev, ndev); | 978 | dev_set_drvdata(&op->dev, ndev); |
1061 | 979 | ||
@@ -1065,6 +983,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | |||
1065 | /* Error handling - free everything that might be allocated */ | 983 | /* Error handling - free everything that might be allocated */ |
1066 | probe_error: | 984 | probe_error: |
1067 | 985 | ||
986 | if (priv->phy_node) | ||
987 | of_node_put(priv->phy_node); | ||
988 | priv->phy_node = NULL; | ||
989 | |||
1068 | irq_dispose_mapping(ndev->irq); | 990 | irq_dispose_mapping(ndev->irq); |
1069 | 991 | ||
1070 | if (priv->rx_dmatsk) | 992 | if (priv->rx_dmatsk) |
@@ -1093,6 +1015,10 @@ mpc52xx_fec_remove(struct of_device *op) | |||
1093 | 1015 | ||
1094 | unregister_netdev(ndev); | 1016 | unregister_netdev(ndev); |
1095 | 1017 | ||
1018 | if (priv->phy_node) | ||
1019 | of_node_put(priv->phy_node); | ||
1020 | priv->phy_node = NULL; | ||
1021 | |||
1096 | irq_dispose_mapping(ndev->irq); | 1022 | irq_dispose_mapping(ndev->irq); |
1097 | 1023 | ||
1098 | bcom_fec_rx_release(priv->rx_dmatsk); | 1024 | bcom_fec_rx_release(priv->rx_dmatsk); |