diff options
author | Haiying Wang <Haiying.Wang@freescale.com> | 2009-06-17 09:16:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-17 21:46:45 -0400 |
commit | fb1001f3de1a8576b25d929502f1fe7865ff32dc (patch) | |
tree | afb9115df813d278e7747ccfc6c138464fe92a23 /drivers/net | |
parent | f3a32500ba8f3ec9ee0c12836fcfd315f1256db4 (diff) |
net/ucc_geth: Add SGMII support for UCC GETH driver
-- derived from reverted commit 047584ce94108012288554a5f84585d792cc7f8f
-- reworked by Grant Likely to play nice with commit:
"net: Rework ucc_geth driver to use of_mdio infrastructure"
(0b9da337dca972e7a4144e298ec3adb8f244d4a4)
Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ucc_geth.c | 58 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 28 |
2 files changed, 84 insertions, 2 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 0cf22c4f123b..255d28d4f84e 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. | 2 | * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Shlomi Gridish <gridish@freescale.com> | 4 | * Author: Shlomi Gridish <gridish@freescale.com> |
5 | * Li Yang <leoli@freescale.com> | 5 | * Li Yang <leoli@freescale.com> |
@@ -1410,6 +1410,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1410 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | 1410 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { |
1411 | upsmr |= UCC_GETH_UPSMR_TBIM; | 1411 | upsmr |= UCC_GETH_UPSMR_TBIM; |
1412 | } | 1412 | } |
1413 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII)) | ||
1414 | upsmr |= UCC_GETH_UPSMR_SGMM; | ||
1415 | |||
1413 | out_be32(&uf_regs->upsmr, upsmr); | 1416 | out_be32(&uf_regs->upsmr, upsmr); |
1414 | 1417 | ||
1415 | /* Disable autonegotiation in tbi mode, because by default it | 1418 | /* Disable autonegotiation in tbi mode, because by default it |
@@ -1531,6 +1534,49 @@ static void adjust_link(struct net_device *dev) | |||
1531 | spin_unlock_irqrestore(&ugeth->lock, flags); | 1534 | spin_unlock_irqrestore(&ugeth->lock, flags); |
1532 | } | 1535 | } |
1533 | 1536 | ||
1537 | /* Initialize TBI PHY interface for communicating with the | ||
1538 | * SERDES lynx PHY on the chip. We communicate with this PHY | ||
1539 | * through the MDIO bus on each controller, treating it as a | ||
1540 | * "normal" PHY at the address found in the UTBIPA register. We assume | ||
1541 | * that the UTBIPA register is valid. Either the MDIO bus code will set | ||
1542 | * it to a value that doesn't conflict with other PHYs on the bus, or the | ||
1543 | * value doesn't matter, as there are no other PHYs on the bus. | ||
1544 | */ | ||
1545 | static void uec_configure_serdes(struct net_device *dev) | ||
1546 | { | ||
1547 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
1548 | struct ucc_geth_info *ug_info = ugeth->ug_info; | ||
1549 | struct phy_device *tbiphy; | ||
1550 | |||
1551 | if (!ug_info->tbi_node) { | ||
1552 | dev_warn(&dev->dev, "SGMII mode requires that the device " | ||
1553 | "tree specify a tbi-handle\n"); | ||
1554 | return; | ||
1555 | } | ||
1556 | |||
1557 | tbiphy = of_phy_find_device(ug_info->tbi_node); | ||
1558 | if (!tbiphy) { | ||
1559 | dev_err(&dev->dev, "error: Could not get TBI device\n"); | ||
1560 | return; | ||
1561 | } | ||
1562 | |||
1563 | /* | ||
1564 | * If the link is already up, we must already be ok, and don't need to | ||
1565 | * configure and reset the TBI<->SerDes link. Maybe U-Boot configured | ||
1566 | * everything for us? Resetting it takes the link down and requires | ||
1567 | * several seconds for it to come back. | ||
1568 | */ | ||
1569 | if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) | ||
1570 | return; | ||
1571 | |||
1572 | /* Single clk mode, mii mode off(for serdes communication) */ | ||
1573 | phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS); | ||
1574 | |||
1575 | phy_write(tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); | ||
1576 | |||
1577 | phy_write(tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS); | ||
1578 | } | ||
1579 | |||
1534 | /* Configure the PHY for dev. | 1580 | /* Configure the PHY for dev. |
1535 | * returns 0 if success. -1 if failure | 1581 | * returns 0 if success. -1 if failure |
1536 | */ | 1582 | */ |
@@ -1554,6 +1600,9 @@ static int init_phy(struct net_device *dev) | |||
1554 | return -ENODEV; | 1600 | return -ENODEV; |
1555 | } | 1601 | } |
1556 | 1602 | ||
1603 | if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) | ||
1604 | uec_configure_serdes(dev); | ||
1605 | |||
1557 | phydev->supported &= (ADVERTISED_10baseT_Half | | 1606 | phydev->supported &= (ADVERTISED_10baseT_Half | |
1558 | ADVERTISED_10baseT_Full | | 1607 | ADVERTISED_10baseT_Full | |
1559 | ADVERTISED_100baseT_Half | | 1608 | ADVERTISED_100baseT_Half | |
@@ -3523,6 +3572,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type) | |||
3523 | return PHY_INTERFACE_MODE_RGMII_RXID; | 3572 | return PHY_INTERFACE_MODE_RGMII_RXID; |
3524 | if (strcasecmp(phy_connection_type, "rtbi") == 0) | 3573 | if (strcasecmp(phy_connection_type, "rtbi") == 0) |
3525 | return PHY_INTERFACE_MODE_RTBI; | 3574 | return PHY_INTERFACE_MODE_RTBI; |
3575 | if (strcasecmp(phy_connection_type, "sgmii") == 0) | ||
3576 | return PHY_INTERFACE_MODE_SGMII; | ||
3526 | 3577 | ||
3527 | return PHY_INTERFACE_MODE_MII; | 3578 | return PHY_INTERFACE_MODE_MII; |
3528 | } | 3579 | } |
@@ -3567,6 +3618,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3567 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, | 3618 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, |
3568 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, | 3619 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, |
3569 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, | 3620 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, |
3621 | PHY_INTERFACE_MODE_SGMII, | ||
3570 | }; | 3622 | }; |
3571 | 3623 | ||
3572 | ugeth_vdbg("%s: IN", __func__); | 3624 | ugeth_vdbg("%s: IN", __func__); |
@@ -3658,6 +3710,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3658 | } | 3710 | } |
3659 | ug_info->phy_node = phy; | 3711 | ug_info->phy_node = phy; |
3660 | 3712 | ||
3713 | /* Find the TBI PHY node. If it's not there, we don't support SGMII */ | ||
3714 | ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0); | ||
3715 | |||
3661 | /* get the phy interface type, or default to MII */ | 3716 | /* get the phy interface type, or default to MII */ |
3662 | prop = of_get_property(np, "phy-connection-type", NULL); | 3717 | prop = of_get_property(np, "phy-connection-type", NULL); |
3663 | if (!prop) { | 3718 | if (!prop) { |
@@ -3682,6 +3737,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3682 | case PHY_INTERFACE_MODE_RGMII_TXID: | 3737 | case PHY_INTERFACE_MODE_RGMII_TXID: |
3683 | case PHY_INTERFACE_MODE_TBI: | 3738 | case PHY_INTERFACE_MODE_TBI: |
3684 | case PHY_INTERFACE_MODE_RTBI: | 3739 | case PHY_INTERFACE_MODE_RTBI: |
3740 | case PHY_INTERFACE_MODE_SGMII: | ||
3685 | max_speed = SPEED_1000; | 3741 | max_speed = SPEED_1000; |
3686 | break; | 3742 | break; |
3687 | default: | 3743 | default: |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index dca628a922ba..1525bf51341c 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | 2 | * Copyright (C) Freescale Semicondutor, Inc. 2006-2009. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Shlomi Gridish <gridish@freescale.com> | 4 | * Author: Shlomi Gridish <gridish@freescale.com> |
5 | * | 5 | * |
@@ -193,6 +193,31 @@ struct ucc_geth { | |||
193 | #define ENET_TBI_MII_JD 0x10 /* Jitter diagnostics */ | 193 | #define ENET_TBI_MII_JD 0x10 /* Jitter diagnostics */ |
194 | #define ENET_TBI_MII_TBICON 0x11 /* TBI control */ | 194 | #define ENET_TBI_MII_TBICON 0x11 /* TBI control */ |
195 | 195 | ||
196 | /* TBI MDIO register bit fields*/ | ||
197 | #define TBISR_LSTATUS 0x0004 | ||
198 | #define TBICON_CLK_SELECT 0x0020 | ||
199 | #define TBIANA_ASYMMETRIC_PAUSE 0x0100 | ||
200 | #define TBIANA_SYMMETRIC_PAUSE 0x0080 | ||
201 | #define TBIANA_HALF_DUPLEX 0x0040 | ||
202 | #define TBIANA_FULL_DUPLEX 0x0020 | ||
203 | #define TBICR_PHY_RESET 0x8000 | ||
204 | #define TBICR_ANEG_ENABLE 0x1000 | ||
205 | #define TBICR_RESTART_ANEG 0x0200 | ||
206 | #define TBICR_FULL_DUPLEX 0x0100 | ||
207 | #define TBICR_SPEED1_SET 0x0040 | ||
208 | |||
209 | #define TBIANA_SETTINGS ( \ | ||
210 | TBIANA_ASYMMETRIC_PAUSE \ | ||
211 | | TBIANA_SYMMETRIC_PAUSE \ | ||
212 | | TBIANA_FULL_DUPLEX \ | ||
213 | ) | ||
214 | #define TBICR_SETTINGS ( \ | ||
215 | TBICR_PHY_RESET \ | ||
216 | | TBICR_ANEG_ENABLE \ | ||
217 | | TBICR_FULL_DUPLEX \ | ||
218 | | TBICR_SPEED1_SET \ | ||
219 | ) | ||
220 | |||
196 | /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ | 221 | /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ |
197 | #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control | 222 | #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control |
198 | Rx */ | 223 | Rx */ |
@@ -1100,6 +1125,7 @@ struct ucc_geth_info { | |||
1100 | u16 pausePeriod; | 1125 | u16 pausePeriod; |
1101 | u16 extensionField; | 1126 | u16 extensionField; |
1102 | struct device_node *phy_node; | 1127 | struct device_node *phy_node; |
1128 | struct device_node *tbi_node; | ||
1103 | u8 weightfactor[NUM_TX_QUEUES]; | 1129 | u8 weightfactor[NUM_TX_QUEUES]; |
1104 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; | 1130 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; |
1105 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; | 1131 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; |