diff options
author | Victor Gallardo <vgallardo@amcc.com> | 2008-10-02 02:37:57 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2008-10-02 13:06:42 -0400 |
commit | 9e3cb29497561c846d0e7efc445731764d93c749 (patch) | |
tree | fec0caf2a561850074bfcb29013603d2fde9b056 /drivers | |
parent | 5a013fc7bb48acefe94011f4b83fef95b381f875 (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')
-rw-r--r-- | drivers/net/ibm_newemac/core.c | 58 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/core.h | 8 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/phy.c | 84 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/phy.h | 2 |
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 | ||
208 | static inline int emac_phy_gpcs(int phy_mode) | 210 | static 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 | ||
41 | static 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 | |||
46 | static 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 | |||
41 | int emac_mii_reset_phy(struct mii_phy *phy) | 51 | int 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 | ||
75 | int 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 | |||
65 | static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) | 106 | static 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 | ||
376 | static 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 | |||
335 | static int et1011c_init(struct mii_phy *phy) | 403 | static 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 | ||
455 | static 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 | |||
463 | static 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 | |||
387 | static struct mii_phy_def *mii_phy_table[] = { | 470 | static 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 | */ |
82 | int emac_mii_phy_probe(struct mii_phy *phy, int address); | 83 | int emac_mii_phy_probe(struct mii_phy *phy, int address); |
83 | int emac_mii_reset_phy(struct mii_phy *phy); | 84 | int emac_mii_reset_phy(struct mii_phy *phy); |
85 | int emac_mii_reset_gpcs(struct mii_phy *phy); | ||
84 | 86 | ||
85 | #endif /* __IBM_NEWEMAC_PHY_H */ | 87 | #endif /* __IBM_NEWEMAC_PHY_H */ |