aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Fleming <afleming@freescale.com>2006-12-01 13:01:06 -0500
committerJeff Garzik <jeff@garzik.org>2006-12-02 00:33:11 -0500
commite8a2b6a4207332a2d59628a12cece9e8c1d769e4 (patch)
tree31028a18413517ed3024450c20cd2e919441b437
parentcabdfb373ae74036225826ce260c16a8e260eb0b (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.txt13
-rw-r--r--drivers/net/au1000_eth.c3
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c3
-rw-r--r--drivers/net/gianfar.c39
-rw-r--r--drivers/net/gianfar.h3
-rw-r--r--drivers/net/phy/phy_device.c29
-rw-r--r--include/linux/phy.h26
7 files changed, 93 insertions, 23 deletions
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
index 29ccae409031..0bc95eab1512 100644
--- a/Documentation/networking/phy.txt
+++ b/Documentation/networking/phy.txt
@@ -1,7 +1,7 @@
1 1
2------- 2-------
3PHY Abstraction Layer 3PHY Abstraction Layer
4(Updated 2005-07-21) 4(Updated 2006-11-30)
5 5
6Purpose 6Purpose
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 7db3c8af0894..f0b6879a1c7d 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 cb3958704a87..889d3a13e95e 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 6bf18c82083d..baa35144134c 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 */
404static 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 9e81a50cf2be..39e9e321fcbc 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 2a08b2b62c4c..b01fc70a57db 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 */
139struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, 140struct 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
188struct phy_device *phy_attach(struct net_device *dev, 190struct 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}
236EXPORT_SYMBOL(phy_attach); 252EXPORT_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
624static int phy_remove(struct device *dev) 635static int phy_remove(struct device *dev)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index ce8bc80b3c86..edd4c88ca7d8 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 */
51typedef 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);
345int phy_clear_interrupt(struct phy_device *phydev); 358int phy_clear_interrupt(struct phy_device *phydev);
346int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); 359int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
347struct phy_device * phy_attach(struct net_device *dev, 360struct 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);
349struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, 362struct 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);
351void phy_disconnect(struct phy_device *phydev); 365void phy_disconnect(struct phy_device *phydev);
352void phy_detach(struct phy_device *phydev); 366void phy_detach(struct phy_device *phydev);
353void phy_start(struct phy_device *phydev); 367void phy_start(struct phy_device *phydev);