aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ibm_newemac
diff options
context:
space:
mode:
authorVictor Gallardo <vgallardo@amcc.com>2008-10-02 02:37:57 -0400
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2008-10-02 13:06:42 -0400
commit9e3cb29497561c846d0e7efc445731764d93c749 (patch)
treefec0caf2a561850074bfcb29013603d2fde9b056 /drivers/net/ibm_newemac
parent5a013fc7bb48acefe94011f4b83fef95b381f875 (diff)
ibm_newemac: Add support for GPCS, SGMII and M88E1112 PHY
Add support for the phy types found on the Arches and other PowerPC 460 based boards. Signed-off-by: Victor Gallardo <vgallardo@amcc.com> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Jeff Garzik <jeff@garzik.org> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/net/ibm_newemac')
-rw-r--r--drivers/net/ibm_newemac/core.c58
-rw-r--r--drivers/net/ibm_newemac/core.h8
-rw-r--r--drivers/net/ibm_newemac/phy.c84
-rw-r--r--drivers/net/ibm_newemac/phy.h2
4 files changed, 143 insertions, 9 deletions
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 4e633870e6e7..efcf21c9f5c7 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -130,6 +130,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev,
130 const char *error) 130 const char *error)
131{ 131{
132 if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | 132 if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
133 EMAC_FTR_460EX_PHY_CLK_FIX |
133 EMAC_FTR_440EP_PHY_CLK_FIX)) 134 EMAC_FTR_440EP_PHY_CLK_FIX))
134 DBG(dev, "%s" NL, error); 135 DBG(dev, "%s" NL, error);
135 else if (net_ratelimit()) 136 else if (net_ratelimit())
@@ -201,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode)
201{ 202{
202 return phy_mode == PHY_MODE_GMII || 203 return phy_mode == PHY_MODE_GMII ||
203 phy_mode == PHY_MODE_RGMII || 204 phy_mode == PHY_MODE_RGMII ||
205 phy_mode == PHY_MODE_SGMII ||
204 phy_mode == PHY_MODE_TBI || 206 phy_mode == PHY_MODE_TBI ||
205 phy_mode == PHY_MODE_RTBI; 207 phy_mode == PHY_MODE_RTBI;
206} 208}
207 209
208static inline int emac_phy_gpcs(int phy_mode) 210static inline int emac_phy_gpcs(int phy_mode)
209{ 211{
210 return phy_mode == PHY_MODE_TBI || 212 return phy_mode == PHY_MODE_SGMII ||
213 phy_mode == PHY_MODE_TBI ||
211 phy_mode == PHY_MODE_RTBI; 214 phy_mode == PHY_MODE_RTBI;
212} 215}
213 216
@@ -351,10 +354,24 @@ static int emac_reset(struct emac_instance *dev)
351 emac_tx_disable(dev); 354 emac_tx_disable(dev);
352 } 355 }
353 356
357#ifdef CONFIG_PPC_DCR_NATIVE
358 /* Enable internal clock source */
359 if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
360 dcri_clrset(SDR0, SDR0_ETH_CFG,
361 0, SDR0_ETH_CFG_ECS << dev->cell_index);
362#endif
363
354 out_be32(&p->mr0, EMAC_MR0_SRST); 364 out_be32(&p->mr0, EMAC_MR0_SRST);
355 while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) 365 while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
356 --n; 366 --n;
357 367
368#ifdef CONFIG_PPC_DCR_NATIVE
369 /* Enable external clock source */
370 if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
371 dcri_clrset(SDR0, SDR0_ETH_CFG,
372 SDR0_ETH_CFG_ECS << dev->cell_index, 0);
373#endif
374
358 if (n) { 375 if (n) {
359 dev->reset_failed = 0; 376 dev->reset_failed = 0;
360 return 0; 377 return 0;
@@ -547,8 +564,9 @@ static int emac_configure(struct emac_instance *dev)
547 switch (dev->phy.speed) { 564 switch (dev->phy.speed) {
548 case SPEED_1000: 565 case SPEED_1000:
549 if (emac_phy_gpcs(dev->phy.mode)) { 566 if (emac_phy_gpcs(dev->phy.mode)) {
550 mr1 |= EMAC_MR1_MF_1000GPCS | 567 mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA(
551 EMAC_MR1_MF_IPPA(dev->phy.address); 568 (dev->phy.gpcs_address != 0xffffffff) ?
569 dev->phy.gpcs_address : dev->phy.address);
552 570
553 /* Put some arbitrary OUI, Manuf & Rev IDs so we can 571 /* Put some arbitrary OUI, Manuf & Rev IDs so we can
554 * identify this GPCS PHY later. 572 * identify this GPCS PHY later.
@@ -660,8 +678,12 @@ static int emac_configure(struct emac_instance *dev)
660 out_be32(&p->iser, r); 678 out_be32(&p->iser, r);
661 679
662 /* We need to take GPCS PHY out of isolate mode after EMAC reset */ 680 /* We need to take GPCS PHY out of isolate mode after EMAC reset */
663 if (emac_phy_gpcs(dev->phy.mode)) 681 if (emac_phy_gpcs(dev->phy.mode)) {
664 emac_mii_reset_phy(&dev->phy); 682 if (dev->phy.gpcs_address != 0xffffffff)
683 emac_mii_reset_gpcs(&dev->phy);
684 else
685 emac_mii_reset_phy(&dev->phy);
686 }
665 687
666 return 0; 688 return 0;
667} 689}
@@ -866,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg)
866 struct emac_instance *dev = netdev_priv(ndev); 888 struct emac_instance *dev = netdev_priv(ndev);
867 int res; 889 int res;
868 890
869 res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev, 891 res = __emac_mdio_read((dev->mdio_instance &&
892 dev->phy.gpcs_address != id) ?
893 dev->mdio_instance : dev,
870 (u8) id, (u8) reg); 894 (u8) id, (u8) reg);
871 return res; 895 return res;
872} 896}
@@ -875,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
875{ 899{
876 struct emac_instance *dev = netdev_priv(ndev); 900 struct emac_instance *dev = netdev_priv(ndev);
877 901
878 __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev, 902 __emac_mdio_write((dev->mdio_instance &&
903 dev->phy.gpcs_address != id) ?
904 dev->mdio_instance : dev,
879 (u8) id, (u8) reg, (u16) val); 905 (u8) id, (u8) reg, (u16) val);
880} 906}
881 907
@@ -2367,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
2367 * XXX I probably should move these settings to the dev tree 2393 * XXX I probably should move these settings to the dev tree
2368 */ 2394 */
2369 dev->phy.address = -1; 2395 dev->phy.address = -1;
2370 dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; 2396 dev->phy.features = SUPPORTED_MII;
2397 if (emac_phy_supports_gige(dev->phy_mode))
2398 dev->phy.features |= SUPPORTED_1000baseT_Full;
2399 else
2400 dev->phy.features |= SUPPORTED_100baseT_Full;
2371 dev->phy.pause = 1; 2401 dev->phy.pause = 1;
2372 2402
2373 return 0; 2403 return 0;
@@ -2406,7 +2436,9 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
2406 * Note that the busy_phy_map is currently global 2436 * Note that the busy_phy_map is currently global
2407 * while it should probably be per-ASIC... 2437 * while it should probably be per-ASIC...
2408 */ 2438 */
2409 dev->phy.address = dev->cell_index; 2439 dev->phy.gpcs_address = dev->gpcs_address;
2440 if (dev->phy.gpcs_address == 0xffffffff)
2441 dev->phy.address = dev->cell_index;
2410 } 2442 }
2411 2443
2412 emac_configure(dev); 2444 emac_configure(dev);
@@ -2516,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev)
2516 dev->phy_address = 0xffffffff; 2548 dev->phy_address = 0xffffffff;
2517 if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) 2549 if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
2518 dev->phy_map = 0xffffffff; 2550 dev->phy_map = 0xffffffff;
2551 if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0))
2552 dev->gpcs_address = 0xffffffff;
2519 if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) 2553 if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
2520 return -ENXIO; 2554 return -ENXIO;
2521 if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) 2555 if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
@@ -2559,6 +2593,9 @@ static int __devinit emac_init_config(struct emac_instance *dev)
2559 /* Check EMAC version */ 2593 /* Check EMAC version */
2560 if (of_device_is_compatible(np, "ibm,emac4sync")) { 2594 if (of_device_is_compatible(np, "ibm,emac4sync")) {
2561 dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC); 2595 dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC);
2596 if (of_device_is_compatible(np, "ibm,emac-460ex") ||
2597 of_device_is_compatible(np, "ibm,emac-460gt"))
2598 dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX;
2562 } else if (of_device_is_compatible(np, "ibm,emac4")) { 2599 } else if (of_device_is_compatible(np, "ibm,emac4")) {
2563 dev->features |= EMAC_FTR_EMAC4; 2600 dev->features |= EMAC_FTR_EMAC4;
2564 if (of_device_is_compatible(np, "ibm,emac-440gx")) 2601 if (of_device_is_compatible(np, "ibm,emac-440gx"))
@@ -2826,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev,
2826 ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], 2863 ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
2827 ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); 2864 ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
2828 2865
2866 if (dev->phy_mode == PHY_MODE_SGMII)
2867 printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);
2868
2829 if (dev->phy.address >= 0) 2869 if (dev->phy.address >= 0)
2830 printk("%s: found %s PHY (0x%02x)\n", ndev->name, 2870 printk("%s: found %s PHY (0x%02x)\n", ndev->name,
2831 dev->phy.def->name, dev->phy.address); 2871 dev->phy.def->name, dev->phy.address);
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index 59e5a5d802f3..18d56c6c4238 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -190,6 +190,9 @@ struct emac_instance {
190 struct delayed_work link_work; 190 struct delayed_work link_work;
191 int link_polling; 191 int link_polling;
192 192
193 /* GPCS PHY infos */
194 u32 gpcs_address;
195
193 /* Shared MDIO if any */ 196 /* Shared MDIO if any */
194 u32 mdio_ph; 197 u32 mdio_ph;
195 struct of_device *mdio_dev; 198 struct of_device *mdio_dev;
@@ -317,6 +320,10 @@ struct emac_instance {
317 * The 405EX and 460EX contain the EMAC4SYNC core 320 * The 405EX and 460EX contain the EMAC4SYNC core
318 */ 321 */
319#define EMAC_FTR_EMAC4SYNC 0x00000200 322#define EMAC_FTR_EMAC4SYNC 0x00000200
323/*
324 * Set if we need phy clock workaround for 460ex or 460gt
325 */
326#define EMAC_FTR_460EX_PHY_CLK_FIX 0x00000400
320 327
321 328
322/* Right now, we don't quite handle the always/possible masks on the 329/* Right now, we don't quite handle the always/possible masks on the
@@ -344,6 +351,7 @@ enum {
344#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL 351#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL
345 EMAC_FTR_NO_FLOW_CONTROL_40x | 352 EMAC_FTR_NO_FLOW_CONTROL_40x |
346#endif 353#endif
354 EMAC_FTR_460EX_PHY_CLK_FIX |
347 EMAC_FTR_440EP_PHY_CLK_FIX, 355 EMAC_FTR_440EP_PHY_CLK_FIX,
348}; 356};
349 357
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c
index 37bfeea8788a..606db53ef78e 100644
--- a/drivers/net/ibm_newemac/phy.c
+++ b/drivers/net/ibm_newemac/phy.c
@@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val)
38 phy->mdio_write(phy->dev, phy->address, reg, val); 38 phy->mdio_write(phy->dev, phy->address, reg, val);
39} 39}
40 40
41static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
42{
43 return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
44}
45
46static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
47{
48 phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
49}
50
41int emac_mii_reset_phy(struct mii_phy *phy) 51int emac_mii_reset_phy(struct mii_phy *phy)
42{ 52{
43 int val; 53 int val;
@@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy)
62 return limit <= 0; 72 return limit <= 0;
63} 73}
64 74
75int emac_mii_reset_gpcs(struct mii_phy *phy)
76{
77 int val;
78 int limit = 10000;
79
80 val = gpcs_phy_read(phy, MII_BMCR);
81 val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
82 val |= BMCR_RESET;
83 gpcs_phy_write(phy, MII_BMCR, val);
84
85 udelay(300);
86
87 while (limit--) {
88 val = gpcs_phy_read(phy, MII_BMCR);
89 if (val >= 0 && (val & BMCR_RESET) == 0)
90 break;
91 udelay(10);
92 }
93 if ((val & BMCR_ISOLATE) && limit > 0)
94 gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
95
96 if (limit > 0 && phy->mode == PHY_MODE_SGMII) {
97 /* Configure GPCS interface to recommended setting for SGMII */
98 gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
99 gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
100 gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */
101 }
102
103 return limit <= 0;
104}
105
65static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) 106static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
66{ 107{
67 int ctl, adv; 108 int ctl, adv;
@@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy)
332 return 0; 373 return 0;
333} 374}
334 375
376static int m88e1112_init(struct mii_phy *phy)
377{
378 /*
379 * Marvell 88E1112 PHY needs to have the SGMII MAC
380 * interace (page 2) properly configured to
381 * communicate with the 460EX/GT GPCS interface.
382 */
383
384 u16 reg_short;
385
386 pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);
387
388 /* Set access to Page 2 */
389 phy_write(phy, 0x16, 0x0002);
390
391 phy_write(phy, 0x00, 0x0040); /* 1Gbps */
392 reg_short = (u16)(phy_read(phy, 0x1a));
393 reg_short |= 0x8000; /* bypass Auto-Negotiation */
394 phy_write(phy, 0x1a, reg_short);
395 emac_mii_reset_phy(phy); /* reset MAC interface */
396
397 /* Reset access to Page 0 */
398 phy_write(phy, 0x16, 0x0000);
399
400 return 0;
401}
402
335static int et1011c_init(struct mii_phy *phy) 403static int et1011c_init(struct mii_phy *phy)
336{ 404{
337 u16 reg_short; 405 u16 reg_short;
@@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = {
384 .ops = &m88e1111_phy_ops, 452 .ops = &m88e1111_phy_ops,
385}; 453};
386 454
455static struct mii_phy_ops m88e1112_phy_ops = {
456 .init = m88e1112_init,
457 .setup_aneg = genmii_setup_aneg,
458 .setup_forced = genmii_setup_forced,
459 .poll_link = genmii_poll_link,
460 .read_link = genmii_read_link
461};
462
463static struct mii_phy_def m88e1112_phy_def = {
464 .phy_id = 0x01410C90,
465 .phy_id_mask = 0x0ffffff0,
466 .name = "Marvell 88E1112 Ethernet",
467 .ops = &m88e1112_phy_ops,
468};
469
387static struct mii_phy_def *mii_phy_table[] = { 470static struct mii_phy_def *mii_phy_table[] = {
388 &et1011c_phy_def, 471 &et1011c_phy_def,
389 &cis8201_phy_def, 472 &cis8201_phy_def,
390 &bcm5248_phy_def, 473 &bcm5248_phy_def,
391 &m88e1111_phy_def, 474 &m88e1111_phy_def,
475 &m88e1112_phy_def,
392 &genmii_phy_def, 476 &genmii_phy_def,
393 NULL 477 NULL
394}; 478};
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h
index 1b65c81f6557..5d2bf4cbe50b 100644
--- a/drivers/net/ibm_newemac/phy.h
+++ b/drivers/net/ibm_newemac/phy.h
@@ -57,6 +57,7 @@ struct mii_phy {
57 or determined automaticaly */ 57 or determined automaticaly */
58 int address; /* PHY address */ 58 int address; /* PHY address */
59 int mode; /* PHY mode */ 59 int mode; /* PHY mode */
60 int gpcs_address; /* GPCS PHY address */
60 61
61 /* 1: autoneg enabled, 0: disabled */ 62 /* 1: autoneg enabled, 0: disabled */
62 int autoneg; 63 int autoneg;
@@ -81,5 +82,6 @@ struct mii_phy {
81 */ 82 */
82int emac_mii_phy_probe(struct mii_phy *phy, int address); 83int emac_mii_phy_probe(struct mii_phy *phy, int address);
83int emac_mii_reset_phy(struct mii_phy *phy); 84int emac_mii_reset_phy(struct mii_phy *phy);
85int emac_mii_reset_gpcs(struct mii_phy *phy);
84 86
85#endif /* __IBM_NEWEMAC_PHY_H */ 87#endif /* __IBM_NEWEMAC_PHY_H */