aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fec_mpc52xx.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2009-04-25 08:53:02 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-27 05:53:47 -0400
commitca816d98170942371535b3e862813b0aba9b7d90 (patch)
tree1321117c2ea1e35a9f00303d2677e603e09ebfca /drivers/net/fec_mpc52xx.c
parent8bc487d150b939e69830c39322df4ee486efe381 (diff)
net: Rework mpc5200 fec driver to use of_mdio infrastructure.
The patch reworks the MPC5200 Fast Ethernet Controller (FEC) driver to use the of_mdio infrastructure for registering PHY devices from data out openfirmware device tree, and eliminates the assumption that the PHY for the FEC is always attached to the FEC's own MDIO bus. With this patch, the FEC can use a PHY attached to any MDIO bus if it is described in the device tree. Tested on Freescale Lite5200b eval board Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Andy Fleming <afleming@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fec_mpc52xx.c')
-rw-r--r--drivers/net/fec_mpc52xx.c180
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 */
50struct mpc52xx_fec_priv { 48struct 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
214static 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
240static 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
261static 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
274static 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
284static int mpc52xx_fec_open(struct net_device *dev) 214static 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 */
1066probe_error: 984probe_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);