diff options
author | Andy Fleming <afleming@freescale.com> | 2006-12-01 13:01:06 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-02 00:33:11 -0500 |
commit | e8a2b6a4207332a2d59628a12cece9e8c1d769e4 (patch) | |
tree | 31028a18413517ed3024450c20cd2e919441b437 | |
parent | cabdfb373ae74036225826ce260c16a8e260eb0b (diff) |
[PATCH] PHY: Add support for configuring the PHY connection interface
Most PHYs connect to an ethernet controller over a GMII or MII
interface. However, a growing number are connected over
different interfaces, such as RGMII or SGMII.
The ethernet driver will tell the PHY what type of connection it
is by setting it manually, or passing it in through phy_connect
(or phy_attach).
Changes include:
* Updates to documentation
* Updates to PHY Lib consumers
* Changes to PHY Lib to add interface support
* Some minor changes to whitespace in phy.h
* gianfar driver now detects interface and passes appropriate
value to PHY Lib
Signed-off-by: Andrew Fleming <afleming@freescale.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | Documentation/networking/phy.txt | 13 | ||||
-rw-r--r-- | drivers/net/au1000_eth.c | 3 | ||||
-rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 3 | ||||
-rw-r--r-- | drivers/net/gianfar.c | 39 | ||||
-rw-r--r-- | drivers/net/gianfar.h | 3 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 29 | ||||
-rw-r--r-- | include/linux/phy.h | 26 |
7 files changed, 93 insertions, 23 deletions
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index 29ccae40903..0bc95eab151 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | ------- | 2 | ------- |
3 | PHY Abstraction Layer | 3 | PHY Abstraction Layer |
4 | (Updated 2005-07-21) | 4 | (Updated 2006-11-30) |
5 | 5 | ||
6 | Purpose | 6 | Purpose |
7 | 7 | ||
@@ -97,11 +97,12 @@ Letting the PHY Abstraction Layer do Everything | |||
97 | 97 | ||
98 | Next, you need to know the device name of the PHY connected to this device. | 98 | Next, you need to know the device name of the PHY connected to this device. |
99 | The name will look something like, "phy0:0", where the first number is the | 99 | The name will look something like, "phy0:0", where the first number is the |
100 | bus id, and the second is the PHY's address on that bus. | 100 | bus id, and the second is the PHY's address on that bus. Typically, |
101 | the bus is responsible for making its ID unique. | ||
101 | 102 | ||
102 | Now, to connect, just call this function: | 103 | Now, to connect, just call this function: |
103 | 104 | ||
104 | phydev = phy_connect(dev, phy_name, &adjust_link, flags); | 105 | phydev = phy_connect(dev, phy_name, &adjust_link, flags, interface); |
105 | 106 | ||
106 | phydev is a pointer to the phy_device structure which represents the PHY. If | 107 | phydev is a pointer to the phy_device structure which represents the PHY. If |
107 | phy_connect is successful, it will return the pointer. dev, here, is the | 108 | phy_connect is successful, it will return the pointer. dev, here, is the |
@@ -115,6 +116,10 @@ Letting the PHY Abstraction Layer do Everything | |||
115 | This is useful if the system has put hardware restrictions on | 116 | This is useful if the system has put hardware restrictions on |
116 | the PHY/controller, of which the PHY needs to be aware. | 117 | the PHY/controller, of which the PHY needs to be aware. |
117 | 118 | ||
119 | interface is a u32 which specifies the connection type used | ||
120 | between the controller and the PHY. Examples are GMII, MII, | ||
121 | RGMII, and SGMII. For a full list, see include/linux/phy.h | ||
122 | |||
118 | Now just make sure that phydev->supported and phydev->advertising have any | 123 | Now just make sure that phydev->supported and phydev->advertising have any |
119 | values pruned from them which don't make sense for your controller (a 10/100 | 124 | values pruned from them which don't make sense for your controller (a 10/100 |
120 | controller may be connected to a gigabit capable PHY, so you would need to | 125 | controller may be connected to a gigabit capable PHY, so you would need to |
@@ -191,7 +196,7 @@ Doing it all yourself | |||
191 | start, or disables then frees them for stop. | 196 | start, or disables then frees them for stop. |
192 | 197 | ||
193 | struct phy_device * phy_attach(struct net_device *dev, const char *phy_id, | 198 | struct phy_device * phy_attach(struct net_device *dev, const char *phy_id, |
194 | u32 flags); | 199 | u32 flags, phy_interface_t interface); |
195 | 200 | ||
196 | Attaches a network device to a particular PHY, binding the PHY to a generic | 201 | Attaches a network device to a particular PHY, binding the PHY to a generic |
197 | driver if none was found during bus initialization. Passes in | 202 | driver if none was found during bus initialization. Passes in |
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 7db3c8af089..f0b6879a1c7 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c | |||
@@ -360,7 +360,8 @@ static int mii_probe (struct net_device *dev) | |||
360 | BUG_ON(!phydev); | 360 | BUG_ON(!phydev); |
361 | BUG_ON(phydev->attached_dev); | 361 | BUG_ON(phydev->attached_dev); |
362 | 362 | ||
363 | phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0); | 363 | phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0, |
364 | PHY_INTERFACE_MODE_MII); | ||
364 | 365 | ||
365 | if (IS_ERR(phydev)) { | 366 | if (IS_ERR(phydev)) { |
366 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | 367 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); |
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index cb3958704a8..889d3a13e95 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
@@ -779,7 +779,8 @@ static int fs_init_phy(struct net_device *dev) | |||
779 | fep->oldspeed = 0; | 779 | fep->oldspeed = 0; |
780 | fep->oldduplex = -1; | 780 | fep->oldduplex = -1; |
781 | if(fep->fpi->bus_id) | 781 | if(fep->fpi->bus_id) |
782 | phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); | 782 | phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, |
783 | PHY_INTERFACE_MODE_MII); | ||
783 | else { | 784 | else { |
784 | printk("No phy bus ID specified in BSP code\n"); | 785 | printk("No phy bus ID specified in BSP code\n"); |
785 | return -EINVAL; | 786 | return -EINVAL; |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6bf18c82083..baa35144134 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * Author: Andy Fleming | 9 | * Author: Andy Fleming |
10 | * Maintainer: Kumar Gala | 10 | * Maintainer: Kumar Gala |
11 | * | 11 | * |
12 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | 12 | * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify it | 14 | * This program is free software; you can redistribute it and/or modify it |
15 | * under the terms of the GNU General Public License as published by the | 15 | * under the terms of the GNU General Public License as published by the |
@@ -398,6 +398,38 @@ static int gfar_remove(struct platform_device *pdev) | |||
398 | } | 398 | } |
399 | 399 | ||
400 | 400 | ||
401 | /* Reads the controller's registers to determine what interface | ||
402 | * connects it to the PHY. | ||
403 | */ | ||
404 | static phy_interface_t gfar_get_interface(struct net_device *dev) | ||
405 | { | ||
406 | struct gfar_private *priv = netdev_priv(dev); | ||
407 | u32 ecntrl = gfar_read(&priv->regs->ecntrl); | ||
408 | |||
409 | if (ecntrl & ECNTRL_SGMII_MODE) | ||
410 | return PHY_INTERFACE_MODE_SGMII; | ||
411 | |||
412 | if (ecntrl & ECNTRL_TBI_MODE) { | ||
413 | if (ecntrl & ECNTRL_REDUCED_MODE) | ||
414 | return PHY_INTERFACE_MODE_RTBI; | ||
415 | else | ||
416 | return PHY_INTERFACE_MODE_TBI; | ||
417 | } | ||
418 | |||
419 | if (ecntrl & ECNTRL_REDUCED_MODE) { | ||
420 | if (ecntrl & ECNTRL_REDUCED_MII_MODE) | ||
421 | return PHY_INTERFACE_MODE_RMII; | ||
422 | else | ||
423 | return PHY_INTERFACE_MODE_RGMII; | ||
424 | } | ||
425 | |||
426 | if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) | ||
427 | return PHY_INTERFACE_MODE_GMII; | ||
428 | |||
429 | return PHY_INTERFACE_MODE_MII; | ||
430 | } | ||
431 | |||
432 | |||
401 | /* Initializes driver's PHY state, and attaches to the PHY. | 433 | /* Initializes driver's PHY state, and attaches to the PHY. |
402 | * Returns 0 on success. | 434 | * Returns 0 on success. |
403 | */ | 435 | */ |
@@ -409,6 +441,7 @@ static int init_phy(struct net_device *dev) | |||
409 | SUPPORTED_1000baseT_Full : 0; | 441 | SUPPORTED_1000baseT_Full : 0; |
410 | struct phy_device *phydev; | 442 | struct phy_device *phydev; |
411 | char phy_id[BUS_ID_SIZE]; | 443 | char phy_id[BUS_ID_SIZE]; |
444 | phy_interface_t interface; | ||
412 | 445 | ||
413 | priv->oldlink = 0; | 446 | priv->oldlink = 0; |
414 | priv->oldspeed = 0; | 447 | priv->oldspeed = 0; |
@@ -416,7 +449,9 @@ static int init_phy(struct net_device *dev) | |||
416 | 449 | ||
417 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); | 450 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); |
418 | 451 | ||
419 | phydev = phy_connect(dev, phy_id, &adjust_link, 0); | 452 | interface = gfar_get_interface(dev); |
453 | |||
454 | phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface); | ||
420 | 455 | ||
421 | if (IS_ERR(phydev)) { | 456 | if (IS_ERR(phydev)) { |
422 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | 457 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); |
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 9e81a50cf2b..39e9e321fcb 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h | |||
@@ -160,7 +160,10 @@ extern const char gfar_driver_version[]; | |||
160 | 160 | ||
161 | #define ECNTRL_INIT_SETTINGS 0x00001000 | 161 | #define ECNTRL_INIT_SETTINGS 0x00001000 |
162 | #define ECNTRL_TBI_MODE 0x00000020 | 162 | #define ECNTRL_TBI_MODE 0x00000020 |
163 | #define ECNTRL_REDUCED_MODE 0x00000010 | ||
163 | #define ECNTRL_R100 0x00000008 | 164 | #define ECNTRL_R100 0x00000008 |
165 | #define ECNTRL_REDUCED_MII_MODE 0x00000004 | ||
166 | #define ECNTRL_SGMII_MODE 0x00000002 | ||
164 | 167 | ||
165 | #define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE | 168 | #define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE |
166 | 169 | ||
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2a08b2b62c4..b01fc70a57d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -59,6 +59,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) | |||
59 | dev->duplex = -1; | 59 | dev->duplex = -1; |
60 | dev->pause = dev->asym_pause = 0; | 60 | dev->pause = dev->asym_pause = 0; |
61 | dev->link = 1; | 61 | dev->link = 1; |
62 | dev->interface = PHY_INTERFACE_MODE_GMII; | ||
62 | 63 | ||
63 | dev->autoneg = AUTONEG_ENABLE; | 64 | dev->autoneg = AUTONEG_ENABLE; |
64 | 65 | ||
@@ -137,11 +138,12 @@ void phy_prepare_link(struct phy_device *phydev, | |||
137 | * the desired functionality. | 138 | * the desired functionality. |
138 | */ | 139 | */ |
139 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, | 140 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, |
140 | void (*handler)(struct net_device *), u32 flags) | 141 | void (*handler)(struct net_device *), u32 flags, |
142 | u32 interface) | ||
141 | { | 143 | { |
142 | struct phy_device *phydev; | 144 | struct phy_device *phydev; |
143 | 145 | ||
144 | phydev = phy_attach(dev, phy_id, flags); | 146 | phydev = phy_attach(dev, phy_id, flags, interface); |
145 | 147 | ||
146 | if (IS_ERR(phydev)) | 148 | if (IS_ERR(phydev)) |
147 | return phydev; | 149 | return phydev; |
@@ -186,7 +188,7 @@ static int phy_compare_id(struct device *dev, void *data) | |||
186 | } | 188 | } |
187 | 189 | ||
188 | struct phy_device *phy_attach(struct net_device *dev, | 190 | struct phy_device *phy_attach(struct net_device *dev, |
189 | const char *phy_id, u32 flags) | 191 | const char *phy_id, u32 flags, u32 interface) |
190 | { | 192 | { |
191 | struct bus_type *bus = &mdio_bus_type; | 193 | struct bus_type *bus = &mdio_bus_type; |
192 | struct phy_device *phydev; | 194 | struct phy_device *phydev; |
@@ -231,6 +233,20 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
231 | 233 | ||
232 | phydev->dev_flags = flags; | 234 | phydev->dev_flags = flags; |
233 | 235 | ||
236 | phydev->interface = interface; | ||
237 | |||
238 | /* Do initial configuration here, now that | ||
239 | * we have certain key parameters | ||
240 | * (dev_flags and interface) */ | ||
241 | if (phydev->drv->config_init) { | ||
242 | int err; | ||
243 | |||
244 | err = phydev->drv->config_init(phydev); | ||
245 | |||
246 | if (err < 0) | ||
247 | return ERR_PTR(err); | ||
248 | } | ||
249 | |||
234 | return phydev; | 250 | return phydev; |
235 | } | 251 | } |
236 | EXPORT_SYMBOL(phy_attach); | 252 | EXPORT_SYMBOL(phy_attach); |
@@ -612,13 +628,8 @@ static int phy_probe(struct device *dev) | |||
612 | 628 | ||
613 | spin_unlock(&phydev->lock); | 629 | spin_unlock(&phydev->lock); |
614 | 630 | ||
615 | if (err < 0) | ||
616 | return err; | ||
617 | |||
618 | if (phydev->drv->config_init) | ||
619 | err = phydev->drv->config_init(phydev); | ||
620 | |||
621 | return err; | 631 | return err; |
632 | |||
622 | } | 633 | } |
623 | 634 | ||
624 | static int phy_remove(struct device *dev) | 635 | static int phy_remove(struct device *dev) |
diff --git a/include/linux/phy.h b/include/linux/phy.h index ce8bc80b3c8..edd4c88ca7d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h | |||
@@ -47,15 +47,26 @@ | |||
47 | #define PHY_HAS_INTERRUPT 0x00000001 | 47 | #define PHY_HAS_INTERRUPT 0x00000001 |
48 | #define PHY_HAS_MAGICANEG 0x00000002 | 48 | #define PHY_HAS_MAGICANEG 0x00000002 |
49 | 49 | ||
50 | /* Interface Mode definitions */ | ||
51 | typedef enum { | ||
52 | PHY_INTERFACE_MODE_MII, | ||
53 | PHY_INTERFACE_MODE_GMII, | ||
54 | PHY_INTERFACE_MODE_SGMII, | ||
55 | PHY_INTERFACE_MODE_TBI, | ||
56 | PHY_INTERFACE_MODE_RMII, | ||
57 | PHY_INTERFACE_MODE_RGMII, | ||
58 | PHY_INTERFACE_MODE_RTBI | ||
59 | } phy_interface_t; | ||
60 | |||
50 | #define MII_BUS_MAX 4 | 61 | #define MII_BUS_MAX 4 |
51 | 62 | ||
52 | 63 | ||
53 | #define PHY_INIT_TIMEOUT 100000 | 64 | #define PHY_INIT_TIMEOUT 100000 |
54 | #define PHY_STATE_TIME 1 | 65 | #define PHY_STATE_TIME 1 |
55 | #define PHY_FORCE_TIMEOUT 10 | 66 | #define PHY_FORCE_TIMEOUT 10 |
56 | #define PHY_AN_TIMEOUT 10 | 67 | #define PHY_AN_TIMEOUT 10 |
57 | 68 | ||
58 | #define PHY_MAX_ADDR 32 | 69 | #define PHY_MAX_ADDR 32 |
59 | 70 | ||
60 | /* Used when trying to connect to a specific phy (mii bus id:phy device id) */ | 71 | /* Used when trying to connect to a specific phy (mii bus id:phy device id) */ |
61 | #define PHY_ID_FMT "%x:%02x" | 72 | #define PHY_ID_FMT "%x:%02x" |
@@ -87,8 +98,8 @@ struct mii_bus { | |||
87 | int *irq; | 98 | int *irq; |
88 | }; | 99 | }; |
89 | 100 | ||
90 | #define PHY_INTERRUPT_DISABLED 0x0 | 101 | #define PHY_INTERRUPT_DISABLED 0x0 |
91 | #define PHY_INTERRUPT_ENABLED 0x80000000 | 102 | #define PHY_INTERRUPT_ENABLED 0x80000000 |
92 | 103 | ||
93 | /* PHY state machine states: | 104 | /* PHY state machine states: |
94 | * | 105 | * |
@@ -230,6 +241,8 @@ struct phy_device { | |||
230 | 241 | ||
231 | u32 dev_flags; | 242 | u32 dev_flags; |
232 | 243 | ||
244 | phy_interface_t interface; | ||
245 | |||
233 | /* Bus address of the PHY (0-32) */ | 246 | /* Bus address of the PHY (0-32) */ |
234 | int addr; | 247 | int addr; |
235 | 248 | ||
@@ -345,9 +358,10 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr); | |||
345 | int phy_clear_interrupt(struct phy_device *phydev); | 358 | int phy_clear_interrupt(struct phy_device *phydev); |
346 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); | 359 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); |
347 | struct phy_device * phy_attach(struct net_device *dev, | 360 | struct phy_device * phy_attach(struct net_device *dev, |
348 | const char *phy_id, u32 flags); | 361 | const char *phy_id, u32 flags, phy_interface_t interface); |
349 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, | 362 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, |
350 | void (*handler)(struct net_device *), u32 flags); | 363 | void (*handler)(struct net_device *), u32 flags, |
364 | phy_interface_t interface); | ||
351 | void phy_disconnect(struct phy_device *phydev); | 365 | void phy_disconnect(struct phy_device *phydev); |
352 | void phy_detach(struct phy_device *phydev); | 366 | void phy_detach(struct phy_device *phydev); |
353 | void phy_start(struct phy_device *phydev); | 367 | void phy_start(struct phy_device *phydev); |