* [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29
@ 2014-08-29 15:21 Tom Lendacky
2014-08-29 15:21 ` [PATCH net-next v1 1/3] amd-xgbe: Move phy driver support into the network driver Tom Lendacky
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Tom Lendacky @ 2014-08-29 15:21 UTC (permalink / raw)
To: netdev; +Cc: davem
The amd-xgbe-phy phylib driver support is integral to the amd-xgbe
driver and isn't meant to be used by other devices. For this reason
it is being removed from the driver/net/phy directory and integrated
into the amd-xgbe driver.
The following series of patches accomplishes this as well as providing
some updates to parallel detection during auto-negotiation.
- Move phylib driver into network driver
- Update device tree bindings to move the phy device resources and
properties into the network device while maintaining backwards
compatibility
- Update parallel detection logic to support KR mode
This patch series is based on net-next.
---
Tom Lendacky (3):
amd-xgbe: Move phy driver support into the network driver
amd-xgbe: Move the phy device resources into network device
amd-xgbe: Enhance auto-negotiation parallel detection
.../devicetree/bindings/net/amd-xgbe-phy.txt | 23
Documentation/devicetree/bindings/net/amd-xgbe.txt | 18
drivers/net/ethernet/amd/Kconfig | 1
drivers/net/ethernet/amd/xgbe/Makefile | 2
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 16
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 10
drivers/net/ethernet/amd/xgbe/xgbe-main.c | 165 ++
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 39 -
drivers/net/ethernet/amd/xgbe/xgbe-phy.c | 1145 ++++++++++++++++
drivers/net/ethernet/amd/xgbe/xgbe.h | 67 +
drivers/net/phy/Kconfig | 6
drivers/net/phy/Makefile | 1
drivers/net/phy/amd-xgbe-phy.c | 1457 --------------------
13 files changed, 1385 insertions(+), 1565 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
create mode 100644 drivers/net/ethernet/amd/xgbe/xgbe-phy.c
delete mode 100644 drivers/net/phy/amd-xgbe-phy.c
--
Tom Lendacky
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next v1 1/3] amd-xgbe: Move phy driver support into the network driver
2014-08-29 15:21 [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 Tom Lendacky
@ 2014-08-29 15:21 ` Tom Lendacky
2014-08-29 15:22 ` [PATCH net-next v1 2/3] amd-xgbe: Move the phy device resources into network device Tom Lendacky
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Tom Lendacky @ 2014-08-29 15:21 UTC (permalink / raw)
To: netdev; +Cc: davem
The phy driver support is not available as a generic phy device for
use by other drivers, it is integral to the amd-xgbe device. For
this reason, remove it from drivers/net/phy directory and make it
part of the amd-xgbe driver. The driver will still make use of the
phy library support for tracking state, etc.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/Kconfig | 1
drivers/net/ethernet/amd/xgbe/Makefile | 2
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 16
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 10
drivers/net/ethernet/amd/xgbe/xgbe-main.c | 137 ++
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 39 -
drivers/net/ethernet/amd/xgbe/xgbe-phy.c | 1128 ++++++++++++++++++++
drivers/net/ethernet/amd/xgbe/xgbe.h | 59 +
drivers/net/phy/Kconfig | 6
drivers/net/phy/Makefile | 1
drivers/net/phy/amd-xgbe-phy.c | 1457 --------------------------
11 files changed, 1320 insertions(+), 1536 deletions(-)
create mode 100644 drivers/net/ethernet/amd/xgbe/xgbe-phy.c
delete mode 100644 drivers/net/phy/amd-xgbe-phy.c
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 8319c99..dbf4446 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -181,7 +181,6 @@ config AMD_XGBE
tristate "AMD 10GbE Ethernet driver"
depends on OF_NET
select PHYLIB
- select AMD_XGBE_PHY
select BITREVERSE
select CRC32
select PTP_1588_CLOCK
diff --git a/drivers/net/ethernet/amd/xgbe/Makefile b/drivers/net/ethernet/amd/xgbe/Makefile
index 171a7e6..861cf15 100644
--- a/drivers/net/ethernet/amd/xgbe/Makefile
+++ b/drivers/net/ethernet/amd/xgbe/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_AMD_XGBE) += amd-xgbe.o
amd-xgbe-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \
xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \
- xgbe-ptp.o
+ xgbe-ptp.o xgbe-phy.o
amd-xgbe-$(CONFIG_AMD_XGBE_DCB) += xgbe-dcb.o
amd-xgbe-$(CONFIG_DEBUG_FS) += xgbe-debugfs.o
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index dc84f71..61c0975 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -525,7 +525,7 @@ static void xgbe_adjust_link(struct net_device *netdev)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- struct phy_device *phydev = pdata->phydev;
+ struct phy_device *phydev = pdata->phy.phydev;
int new_state = 0;
if (phydev == NULL)
@@ -590,7 +590,7 @@ static void xgbe_adjust_link(struct net_device *netdev)
static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{
struct net_device *netdev = pdata->netdev;
- struct phy_device *phydev = pdata->phydev;
+ struct phy_device *phydev = pdata->phy.phydev;
int ret;
pdata->phy_link = -1;
@@ -623,10 +623,10 @@ err_phy_connect:
static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
{
- if (!pdata->phydev)
+ if (!pdata->phy.phydev)
return;
- phy_disconnect(pdata->phydev);
+ phy_disconnect(pdata->phy.phydev);
}
int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
@@ -644,7 +644,7 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- phy_stop(pdata->phydev);
+ phy_stop(pdata->phy.phydev);
spin_lock_irqsave(&pdata->lock, flags);
@@ -686,7 +686,7 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
pdata->power_down = 0;
- phy_start(pdata->phydev);
+ phy_start(pdata->phy.phydev);
/* Enable Tx/Rx */
hw_if->powerup_tx(pdata);
@@ -716,7 +716,7 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
hw_if->init(pdata);
- phy_start(pdata->phydev);
+ phy_start(pdata->phy.phydev);
hw_if->enable_tx(pdata);
hw_if->enable_rx(pdata);
@@ -738,7 +738,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
DBGPR("-->xgbe_stop\n");
- phy_stop(pdata->phydev);
+ phy_stop(pdata->phy.phydev);
netif_tx_stop_all_queues(netdev);
xgbe_napi_disable(pdata, 1);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index a076aca..033ed55 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -250,7 +250,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct phy_device *phydev = pdata->phydev;
+ struct phy_device *phydev = pdata->phy.phydev;
int ret = 0;
DBGPR("-->xgbe_set_pauseparam\n");
@@ -287,10 +287,10 @@ static int xgbe_get_settings(struct net_device *netdev,
DBGPR("-->xgbe_get_settings\n");
- if (!pdata->phydev)
+ if (!pdata->phy.phydev)
return -ENODEV;
- ret = phy_ethtool_gset(pdata->phydev, cmd);
+ ret = phy_ethtool_gset(pdata->phy.phydev, cmd);
cmd->transceiver = XCVR_EXTERNAL;
DBGPR("<--xgbe_get_settings\n");
@@ -302,13 +302,13 @@ static int xgbe_set_settings(struct net_device *netdev,
struct ethtool_cmd *cmd)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct phy_device *phydev = pdata->phydev;
+ struct phy_device *phydev = pdata->phy.phydev;
u32 speed;
int ret;
DBGPR("-->xgbe_set_settings\n");
- if (!pdata->phydev)
+ if (!pdata->phy.phydev)
return -ENODEV;
speed = ethtool_cmd_speed(cmd);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index 8aa6a93..f9ffbfc 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -122,6 +122,8 @@
#include <linux/etherdevice.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/clk.h>
@@ -223,7 +225,10 @@ static int xgbe_probe(struct platform_device *pdev)
struct xgbe_desc_if *desc_if;
struct net_device *netdev;
struct device *dev = &pdev->dev;
+ struct device_node *phy_node;
+ struct platform_device *phy_pdev;
struct resource *res;
+ const __be32 *property;
const u8 *mac_addr;
int ret;
@@ -247,6 +252,21 @@ static int xgbe_probe(struct platform_device *pdev)
mutex_init(&pdata->xpcs_mutex);
spin_lock_init(&pdata->tstamp_lock);
+ /* Obtain a reference the phy device */
+ phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
+ if (!phy_node) {
+ dev_err(dev, "unable to parse phy-handle\n");
+ ret = -EINVAL;
+ goto err_put;
+ }
+
+ phy_pdev = of_find_device_by_node(phy_node);
+ if (!phy_pdev) {
+ dev_err(dev, "unable to locate phy device\n");
+ ret = -EINVAL;
+ goto err_io;
+ }
+
/* Set and validate the number of descriptors for a ring */
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
pdata->tx_desc_count = XGBE_TX_DESC_CNT;
@@ -300,12 +320,65 @@ static int xgbe_probe(struct platform_device *pdev)
}
DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
- /* Set the DMA mask */
- if (!dev->dma_mask)
- dev->dma_mask = &dev->coherent_dma_mask;
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
- if (ret) {
- dev_err(dev, "dma_set_mask_and_coherent failed\n");
+ /* Obtain the mmio areas for the phy device */
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, 0);
+ pdata->rxtx_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pdata->rxtx_regs)) {
+ dev_err(dev, "rxtx ioremap failed\n");
+ ret = PTR_ERR(pdata->rxtx_regs);
+ goto err_io;
+ }
+ DBGPR(" rxtx_regs = %p\n", pdata->rxtx_regs);
+
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, 1);
+ pdata->sir0_regs = devm_ioremap_nocache(dev, res->start,
+ resource_size(res));
+ if (IS_ERR(pdata->sir0_regs)) {
+ dev_err(dev, "sir0 ioremap failed\n");
+ ret = PTR_ERR(pdata->sir0_regs);
+ goto err_io;
+ }
+ DBGPR(" sir0_regs = %p\n", pdata->sir0_regs);
+
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, 2);
+ pdata->sir1_regs = devm_ioremap_nocache(dev, res->start,
+ resource_size(res));
+ if (IS_ERR(pdata->sir1_regs)) {
+ dev_err(dev, "sir1 ioremap failed\n");
+ ret = PTR_ERR(pdata->sir1_regs);
+ goto err_io;
+ }
+ DBGPR(" sir1_regs = %p\n", pdata->sir1_regs);
+
+ /* Get the device speed set property */
+ property = of_get_property(phy_node, XGBE_PHY_SPEEDSET_PROPERTY, NULL);
+ if (property)
+ pdata->speed_set = be32_to_cpu(*property);
+
+ switch (pdata->speed_set) {
+ case XGBE_PHY_SPEEDSET_1000_10000:
+ case XGBE_PHY_SPEEDSET_2500_10000:
+ break;
+ default:
+ dev_err(dev, "invalid amd,speed-set property\n");
+ ret = -EINVAL;
+ goto err_io;
+ }
+
+ /* Retrieve the MAC address */
+ mac_addr = of_get_mac_address(dev->of_node);
+ if (!mac_addr) {
+ dev_err(dev, "invalid mac address for this device\n");
+ ret = -EINVAL;
+ goto err_io;
+ }
+ memcpy(netdev->dev_addr, mac_addr, netdev->addr_len);
+
+ /* Retrieve the PHY mode - it must be "xgmii" */
+ pdata->phy_mode = of_get_phy_mode(dev->of_node);
+ if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) {
+ dev_err(dev, "invalid phy-mode specified for this device\n");
+ ret = -EINVAL;
goto err_io;
}
@@ -319,6 +392,16 @@ static int xgbe_probe(struct platform_device *pdev)
pdata->awcache = XGBE_DMA_SYS_AWCACHE;
}
+ /* Set the DMA mask */
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+ if (ret) {
+ dev_err(dev, "dma_set_mask_and_coherent failed\n");
+ goto err_io;
+ }
+
+ /* Get the device interrupt */
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(dev, "platform_get_irq failed\n");
@@ -338,23 +421,6 @@ static int xgbe_probe(struct platform_device *pdev)
/* Populate the hardware features */
xgbe_get_all_hw_features(pdata);
- /* Retrieve the MAC address */
- mac_addr = of_get_mac_address(dev->of_node);
- if (!mac_addr) {
- dev_err(dev, "invalid mac address for this device\n");
- ret = -EINVAL;
- goto err_io;
- }
- memcpy(netdev->dev_addr, mac_addr, netdev->addr_len);
-
- /* Retrieve the PHY mode - it must be "xgmii" */
- pdata->phy_mode = of_get_phy_mode(dev->of_node);
- if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) {
- dev_err(dev, "invalid phy-mode specified for this device\n");
- ret = -EINVAL;
- goto err_io;
- }
-
/* Set default configuration data */
xgbe_default_config(pdata);
@@ -447,6 +513,8 @@ static int xgbe_probe(struct platform_device *pdev)
xgbe_debugfs_init(pdata);
+ of_node_put(phy_node);
+
netdev_notice(netdev, "net device enabled\n");
DBGPR("<-- xgbe_probe\n");
@@ -460,6 +528,9 @@ err_bus_id:
kfree(pdata->mii_bus_id);
err_io:
+ of_node_put(phy_node);
+
+err_put:
free_netdev(netdev);
err_alloc:
@@ -550,4 +621,22 @@ static struct platform_driver xgbe_driver = {
.remove = xgbe_remove,
};
-module_platform_driver(xgbe_driver);
+static int __init xgbe_driver_init(void)
+{
+ int ret;
+
+ ret = xgbe_phy_register();
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&xgbe_driver);
+}
+module_init(xgbe_driver_init);
+
+static void __exit xgbe_driver_exit(void)
+{
+ platform_driver_unregister(&xgbe_driver);
+
+ xgbe_phy_unregister();
+}
+module_exit(xgbe_driver_exit);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index 6d2221e..11c4912 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -206,25 +206,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
int xgbe_mdio_register(struct xgbe_prv_data *pdata)
{
- struct device_node *phy_node;
struct mii_bus *mii;
struct phy_device *phydev;
int ret = 0;
DBGPR("-->xgbe_mdio_register\n");
- /* Retrieve the phy-handle */
- phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0);
- if (!phy_node) {
- dev_err(pdata->dev, "unable to parse phy-handle\n");
- return -EINVAL;
- }
-
mii = mdiobus_alloc();
if (mii == NULL) {
dev_err(pdata->dev, "mdiobus_alloc failed\n");
- ret = -ENOMEM;
- goto err_node_get;
+ return -ENOMEM;
}
/* Register on the MDIO bus (don't probe any PHYs) */
@@ -250,24 +241,18 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
ret = phydev ? PTR_ERR(phydev) : -ENOLINK;
goto err_mdiobus_register;
}
- request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT,
- MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS]));
+ phydev->priv = pdata;
- of_node_get(phy_node);
- phydev->dev.of_node = phy_node;
ret = phy_device_register(phydev);
if (ret) {
dev_err(pdata->dev, "phy_device_register failed\n");
- of_node_put(phy_node);
goto err_phy_device;
}
- /* Add a reference to the PHY driver so it can't be unloaded */
- pdata->phy_module = phydev->dev.driver ?
- phydev->dev.driver->owner : NULL;
- if (!try_module_get(pdata->phy_module)) {
- dev_err(pdata->dev, "try_module_get failed\n");
- ret = -EIO;
+ /* Be sure the phy support was probed successfully */
+ if (!pdata->phy.probed) {
+ dev_err(pdata->dev, "phy support not probed successfully\n");
+ ret = -EINVAL;
goto err_phy_device;
}
@@ -282,9 +267,7 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
phydev->advertising &= ~ADVERTISED_Autoneg;
}
- pdata->phydev = phydev;
-
- of_node_put(phy_node);
+ pdata->phy.phydev = phydev;
DBGPHY_REGS(pdata);
@@ -301,9 +284,6 @@ err_mdiobus_register:
err_mdiobus_alloc:
mdiobus_free(mii);
-err_node_get:
- of_node_put(phy_node);
-
return ret;
}
@@ -311,10 +291,7 @@ void xgbe_mdio_unregister(struct xgbe_prv_data *pdata)
{
DBGPR("-->xgbe_mdio_unregister\n");
- pdata->phydev = NULL;
-
- module_put(pdata->phy_module);
- pdata->phy_module = NULL;
+ pdata->phy.phydev = NULL;
mdiobus_unregister(pdata->mii);
pdata->mii->priv = NULL;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
new file mode 100644
index 0000000..7aca21d
--- /dev/null
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
@@ -0,0 +1,1128 @@
+/*
+ * AMD 10Gb Ethernet driver
+ *
+ * This file is available to you under your choice of the following two
+ * licenses:
+ *
+ * License 1: GPLv2
+ *
+ * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ *
+ * This file is free software; you may copy, redistribute and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * License 2: Modified BSD
+ *
+ * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Advanced Micro Devices, Inc. nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mm.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/mdio.h>
+#include <linux/io.h>
+
+#include "xgbe.h"
+#include "xgbe-common.h"
+
+#define XGBE_PHY_ID 0x000162d0
+#define XGBE_PHY_MASK 0xfffffff0
+
+#define XGBE_AN_INT_CMPLT 0x01
+#define XGBE_AN_INC_LINK 0x02
+#define XGBE_AN_PG_RCV 0x04
+
+#define XNP_MCF_NULL_MESSAGE 0x001
+#define XNP_ACK_PROCESSED (1 << 12)
+#define XNP_MP_FORMATTED (1 << 13)
+#define XNP_NP_EXCHANGE (1 << 15)
+
+#define XGBE_PHY_RATECHANGE_COUNT 500
+
+#ifndef MDIO_PMA_10GBR_PMD_CTRL
+#define MDIO_PMA_10GBR_PMD_CTRL 0x0096
+#endif
+
+#ifndef MDIO_PMA_10GBR_FEC_CTRL
+#define MDIO_PMA_10GBR_FEC_CTRL 0x00ab
+#endif
+
+#ifndef MDIO_AN_XNP
+#define MDIO_AN_XNP 0x0016
+#endif
+
+#ifndef MDIO_AN_INTMASK
+#define MDIO_AN_INTMASK 0x8001
+#endif
+
+#ifndef MDIO_AN_INT
+#define MDIO_AN_INT 0x8002
+#endif
+
+#ifndef MDIO_CTRL1_SPEED1G
+#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
+#endif
+
+#ifndef MDIO_PMA_10GBR_KR_TRAIN_START
+#define MDIO_PMA_10GBR_KR_TRAIN_START 0x01
+#endif
+
+#ifndef MDIO_PMA_10GBR_KR_TRAIN_ENABLE
+#define MDIO_PMA_10GBR_KR_TRAIN_ENABLE 0x02
+#endif
+
+/* SerDes integration register offsets */
+#define SIR0_KR_RT_1 0x002c
+#define SIR0_STATUS 0x0040
+#define SIR1_SPEED 0x0000
+
+/* SerDes integration register entry bit positions and sizes */
+#define SIR0_KR_RT_1_RESET_INDEX 11
+#define SIR0_KR_RT_1_RESET_WIDTH 1
+#define SIR0_STATUS_RX_READY_INDEX 0
+#define SIR0_STATUS_RX_READY_WIDTH 1
+#define SIR0_STATUS_TX_READY_INDEX 8
+#define SIR0_STATUS_TX_READY_WIDTH 1
+#define SIR1_SPEED_DATARATE_INDEX 4
+#define SIR1_SPEED_DATARATE_WIDTH 2
+#define SIR1_SPEED_PI_SPD_SEL_INDEX 12
+#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4
+#define SIR1_SPEED_PLLSEL_INDEX 3
+#define SIR1_SPEED_PLLSEL_WIDTH 1
+#define SIR1_SPEED_RATECHANGE_INDEX 6
+#define SIR1_SPEED_RATECHANGE_WIDTH 1
+#define SIR1_SPEED_TXAMP_INDEX 8
+#define SIR1_SPEED_TXAMP_WIDTH 4
+#define SIR1_SPEED_WORDMODE_INDEX 0
+#define SIR1_SPEED_WORDMODE_WIDTH 3
+
+#define SPEED_10000_CDR 0x7
+#define SPEED_10000_PLL 0x1
+#define SPEED_10000_RATE 0x0
+#define SPEED_10000_TXAMP 0xa
+#define SPEED_10000_WORD 0x7
+
+#define SPEED_2500_CDR 0x2
+#define SPEED_2500_PLL 0x0
+#define SPEED_2500_RATE 0x1
+#define SPEED_2500_TXAMP 0xf
+#define SPEED_2500_WORD 0x1
+
+#define SPEED_1000_CDR 0x2
+#define SPEED_1000_PLL 0x0
+#define SPEED_1000_RATE 0x3
+#define SPEED_1000_TXAMP 0xf
+#define SPEED_1000_WORD 0x1
+
+/* SerDes RxTx register offsets */
+#define RXTX_REG20 0x0050
+#define RXTX_REG114 0x01c8
+
+/* SerDes RxTx register entry bit positions and sizes */
+#define RXTX_REG20_BLWC_ENA_INDEX 2
+#define RXTX_REG20_BLWC_ENA_WIDTH 1
+#define RXTX_REG114_PQ_REG_INDEX 9
+#define RXTX_REG114_PQ_REG_WIDTH 7
+
+#define RXTX_10000_BLWC 0
+#define RXTX_10000_PQ 0x1e
+
+#define RXTX_2500_BLWC 1
+#define RXTX_2500_PQ 0xa
+
+#define RXTX_1000_BLWC 1
+#define RXTX_1000_PQ 0xa
+
+/* Bit setting and getting macros
+ * The get macro will extract the current bit field value from within
+ * the variable
+ *
+ * The set macro will clear the current bit field value within the
+ * variable and then set the bit field of the variable to the
+ * specified value
+ */
+#define GET_BITS(_var, _index, _width) \
+ (((_var) >> (_index)) & ((0x1 << (_width)) - 1))
+
+#define SET_BITS(_var, _index, _width, _val) \
+do { \
+ (_var) &= ~(((0x1 << (_width)) - 1) << (_index)); \
+ (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \
+} while (0)
+
+#define XSIR_GET_BITS(_var, _prefix, _field) \
+ GET_BITS((_var), \
+ _prefix##_##_field##_INDEX, \
+ _prefix##_##_field##_WIDTH)
+
+#define XSIR_SET_BITS(_var, _prefix, _field, _val) \
+ SET_BITS((_var), \
+ _prefix##_##_field##_INDEX, \
+ _prefix##_##_field##_WIDTH, (_val))
+
+/* Macros for reading or writing SerDes integration registers
+ * The ioread macros will get bit fields or full values using the
+ * register definitions formed using the input names
+ *
+ * The iowrite macros will set bit fields or full values using the
+ * register definitions formed using the input names
+ */
+#define XSIR0_IOREAD(_pdata, _reg) \
+ ioread16((_pdata)->sir0_regs + _reg)
+
+#define XSIR0_IOREAD_BITS(_pdata, _reg, _field) \
+ GET_BITS(XSIR0_IOREAD((_pdata), _reg), \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH)
+
+#define XSIR0_IOWRITE(_pdata, _reg, _val) \
+ iowrite16((_val), (_pdata)->sir0_regs + _reg)
+
+#define XSIR0_IOWRITE_BITS(_pdata, _reg, _field, _val) \
+do { \
+ u16 reg_val = XSIR0_IOREAD((_pdata), _reg); \
+ SET_BITS(reg_val, \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH, (_val)); \
+ XSIR0_IOWRITE((_pdata), _reg, reg_val); \
+} while (0)
+
+#define XSIR1_IOREAD(_pdata, _reg) \
+ ioread16((_pdata)->sir1_regs + _reg)
+
+#define XSIR1_IOREAD_BITS(_pdata, _reg, _field) \
+ GET_BITS(XSIR1_IOREAD((_pdata), _reg), \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH)
+
+#define XSIR1_IOWRITE(_pdata, _reg, _val) \
+ iowrite16((_val), (_pdata)->sir1_regs + _reg)
+
+#define XSIR1_IOWRITE_BITS(_pdata, _reg, _field, _val) \
+do { \
+ u16 reg_val = XSIR1_IOREAD((_pdata), _reg); \
+ SET_BITS(reg_val, \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH, (_val)); \
+ XSIR1_IOWRITE((_pdata), _reg, reg_val); \
+} while (0)
+
+/* Macros for reading or writing SerDes RxTx registers
+ * The ioread macros will get bit fields or full values using the
+ * register definitions formed using the input names
+ *
+ * The iowrite macros will set bit fields or full values using the
+ * register definitions formed using the input names
+ */
+#define XRXTX_IOREAD(_pdata, _reg) \
+ ioread16((_pdata)->rxtx_regs + _reg)
+
+#define XRXTX_IOREAD_BITS(_pdata, _reg, _field) \
+ GET_BITS(XRXTX_IOREAD((_pdata), _reg), \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH)
+
+#define XRXTX_IOWRITE(_pdata, _reg, _val) \
+ iowrite16((_val), (_pdata)->rxtx_regs + _reg)
+
+#define XRXTX_IOWRITE_BITS(_pdata, _reg, _field, _val) \
+do { \
+ u16 reg_val = XRXTX_IOREAD((_pdata), _reg); \
+ SET_BITS(reg_val, \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH, (_val)); \
+ XRXTX_IOWRITE((_pdata), _reg, reg_val); \
+} while (0)
+
+static void xgbe_phy_an_enable_kr_training(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
+ MDIO_PMA_10GBR_KR_TRAIN_ENABLE,
+ MDIO_PMA_10GBR_KR_TRAIN_ENABLE);
+}
+
+static void xgbe_phy_an_disable_kr_training(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
+ MDIO_PMA_10GBR_KR_TRAIN_ENABLE, 0);
+}
+
+static void xgbe_phy_pcs_power_cycle(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ unsigned int val;
+
+ val = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+
+ val |= MDIO_CTRL1_LPOWER;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, val);
+
+ usleep_range(75, 100);
+
+ val &= ~MDIO_CTRL1_LPOWER;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, val);
+}
+
+static void xgbe_phy_serdes_start_ratechange(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Assert Rx and Tx ratechange */
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1);
+}
+
+static void xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ unsigned int wait;
+ u16 status;
+
+ /* Release Rx and Tx ratechange */
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0);
+
+ /* Wait for Rx and Tx ready */
+ wait = XGBE_PHY_RATECHANGE_COUNT;
+ while (wait--) {
+ usleep_range(50, 75);
+
+ status = XSIR0_IOREAD(pdata, SIR0_STATUS);
+ if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
+ XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
+ return;
+ }
+
+ netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
+ status);
+}
+
+static void xgbe_phy_xgmii_mode(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Enable KR training */
+ xgbe_phy_an_enable_kr_training(phydev);
+
+ /* Set PCS to KR/10G speed */
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_TYPE,
+ MDIO_PCS_CTRL2_10GBR);
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL1, MDIO_CTRL1_SPEEDSEL,
+ MDIO_CTRL1_SPEED10G);
+
+ xgbe_phy_pcs_power_cycle(phydev);
+
+ /* Set SerDes to 10G speed */
+ xgbe_phy_serdes_start_ratechange(phydev);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, SPEED_10000_RATE);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, SPEED_10000_WORD);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, SPEED_10000_PLL);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR);
+
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, RXTX_10000_PQ);
+
+ xgbe_phy_serdes_complete_ratechange(phydev);
+}
+
+static void xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Disable KR training */
+ xgbe_phy_an_disable_kr_training(phydev);
+
+ /* Set PCS to KX/1G speed */
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_TYPE,
+ MDIO_PCS_CTRL2_10GBX);
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL1, MDIO_CTRL1_SPEEDSEL,
+ MDIO_CTRL1_SPEED1G);
+
+ xgbe_phy_pcs_power_cycle(phydev);
+
+ /* Set SerDes to 2.5G speed */
+ xgbe_phy_serdes_start_ratechange(phydev);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, SPEED_2500_RATE);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, SPEED_2500_WORD);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, SPEED_2500_PLL);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR);
+
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, RXTX_2500_PQ);
+
+ xgbe_phy_serdes_complete_ratechange(phydev);
+}
+
+static void xgbe_phy_gmii_mode(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Disable KR training */
+ xgbe_phy_an_disable_kr_training(phydev);
+
+ /* Set PCS to KX/1G speed */
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_TYPE,
+ MDIO_PCS_CTRL2_10GBX);
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL1, MDIO_CTRL1_SPEEDSEL,
+ MDIO_CTRL1_SPEED1G);
+
+ xgbe_phy_pcs_power_cycle(phydev);
+
+ /* Set SerDes to 1G speed */
+ xgbe_phy_serdes_start_ratechange(phydev);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, SPEED_1000_RATE);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, SPEED_1000_WORD);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, SPEED_1000_PLL);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR);
+
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, RXTX_1000_PQ);
+
+ xgbe_phy_serdes_complete_ratechange(phydev);
+}
+
+static enum xgbe_speed_mode xgbe_phy_cur_mode(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ unsigned int val;
+
+ val = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
+ if ((val & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
+ return XGBE_SPEED_MODE_KR;
+
+ return XGBE_SPEED_MODE_KX;
+}
+
+static bool xgbe_phy_in_kr_mode(struct phy_device *phydev)
+{
+ return (xgbe_phy_cur_mode(phydev) == XGBE_SPEED_MODE_KR);
+}
+
+static bool xgbe_phy_in_kx_mode(struct phy_device *phydev)
+{
+ return (xgbe_phy_cur_mode(phydev) == XGBE_SPEED_MODE_KX);
+}
+
+static void xgbe_phy_switch_mode(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* If we are in KR switch to KX, and vice-versa */
+ if (xgbe_phy_in_kr_mode(phydev)) {
+ if (pdata->speed_set == XGBE_PHY_SPEEDSET_1000_10000)
+ xgbe_phy_gmii_mode(phydev);
+ else
+ xgbe_phy_gmii_2500_mode(phydev);
+ } else {
+ xgbe_phy_xgmii_mode(phydev);
+ }
+}
+
+static void xgbe_phy_set_mode(struct phy_device *phydev,
+ enum xgbe_speed_mode mode)
+{
+ if (mode != xgbe_phy_cur_mode(phydev))
+ xgbe_phy_switch_mode(phydev);
+}
+
+static enum xgbe_an xgbe_phy_an_tx_training(struct phy_device *phydev,
+ enum xgbe_an_rx *state)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ int ad_val, lp_val, val;
+
+ *state = XGBE_AN_RX_COMPLETE;
+
+ /* If we're in KX mode then we're done */
+ if (xgbe_phy_in_kx_mode(phydev))
+ return XGBE_AN_EVENT;
+
+ /* Enable/Disable FEC */
+ ad_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
+ lp_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
+
+ val = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL);
+
+ if ((ad_val & 0xc000) && (lp_val & 0xc000))
+ val |= 0x01;
+ else
+ val &= ~0x01;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, val);
+
+ /* Start KR training */
+ XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1);
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
+ MDIO_PMA_10GBR_KR_TRAIN_START,
+ MDIO_PMA_10GBR_KR_TRAIN_START);
+
+ XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0);
+
+ return XGBE_AN_EVENT;
+}
+
+static enum xgbe_an xgbe_phy_an_tx_xnp(struct phy_device *phydev,
+ enum xgbe_an_rx *state)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ u16 msg;
+
+ *state = XGBE_AN_RX_XNP;
+
+ msg = XNP_MCF_NULL_MESSAGE;
+ msg |= XNP_MP_FORMATTED;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
+
+ return XGBE_AN_EVENT;
+}
+
+static enum xgbe_an xgbe_phy_an_rx_bpa(struct phy_device *phydev,
+ enum xgbe_an_rx *state)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ unsigned int link_support;
+ int val, ad_val, lp_val;
+
+ /* Read Base Ability register 2 first */
+ val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
+
+ /* Check for a supported mode, otherwise restart in a different one */
+ link_support = (xgbe_phy_in_kr_mode(phydev)) ? 0x80 : 0x20;
+ if (!(val & link_support))
+ return XGBE_AN_INCOMPAT_LINK;
+
+ /* Check Extended Next Page support */
+ ad_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ lp_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
+
+ return ((ad_val & XNP_NP_EXCHANGE) || (lp_val & XNP_NP_EXCHANGE))
+ ? xgbe_phy_an_tx_xnp(phydev, state)
+ : xgbe_phy_an_tx_training(phydev, state);
+}
+
+static enum xgbe_an xgbe_phy_an_rx_xnp(struct phy_device *phydev,
+ enum xgbe_an_rx *state)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ int ad_val, lp_val;
+
+ /* Check Extended Next Page support */
+ ad_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ lp_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
+
+ return ((ad_val & XNP_NP_EXCHANGE) || (lp_val & XNP_NP_EXCHANGE))
+ ? xgbe_phy_an_tx_xnp(phydev, state)
+ : xgbe_phy_an_tx_training(phydev, state);
+}
+
+static enum xgbe_an xgbe_phy_an_start(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ unsigned int val;
+
+ /* Be sure we aren't looping trying to negotiate */
+ if (xgbe_phy_in_kr_mode(phydev)) {
+ if (pdata->phy.kr_state != XGBE_AN_RX_READY)
+ return XGBE_AN_NO_LINK;
+ pdata->phy.kr_state = XGBE_AN_RX_BPA;
+ } else {
+ if (pdata->phy.kx_state != XGBE_AN_RX_READY)
+ return XGBE_AN_NO_LINK;
+ pdata->phy.kx_state = XGBE_AN_RX_BPA;
+ }
+
+ /* Set up Advertisement register 3 first */
+ val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
+
+ if (phydev->supported & SUPPORTED_10000baseR_FEC)
+ val |= 0xc000;
+ else
+ val &= ~0xc000;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, val);
+
+ /* Set up Advertisement register 2 next */
+ val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
+
+ if (phydev->supported & SUPPORTED_10000baseKR_Full)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+
+ if ((phydev->supported & SUPPORTED_1000baseKX_Full) ||
+ (phydev->supported & SUPPORTED_2500baseX_Full))
+ val |= 0x20;
+ else
+ val &= ~0x20;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, val);
+
+ /* Set up Advertisement register 1 last */
+ val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+
+ if (phydev->supported & SUPPORTED_Pause)
+ val |= 0x400;
+ else
+ val &= ~0x400;
+
+ if (phydev->supported & SUPPORTED_Asym_Pause)
+ val |= 0x800;
+ else
+ val &= ~0x800;
+
+ /* We don't intend to perform XNP */
+ val &= ~XNP_NP_EXCHANGE;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, val);
+
+ /* Enable and start auto-negotiation */
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
+ val |= MDIO_AN_CTRL1_ENABLE;
+ val |= MDIO_AN_CTRL1_RESTART;
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, val);
+
+ return XGBE_AN_EVENT;
+}
+
+static enum xgbe_an xgbe_phy_an_event(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ enum xgbe_an new_state;
+ unsigned int val;
+
+ val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
+
+ new_state = XGBE_AN_EVENT;
+ if (val & XGBE_AN_PG_RCV)
+ new_state = XGBE_AN_PAGE_RECEIVED;
+ else if (val & XGBE_AN_INC_LINK)
+ new_state = XGBE_AN_INCOMPAT_LINK;
+ else if (val & XGBE_AN_INT_CMPLT)
+ new_state = XGBE_AN_COMPLETE;
+
+ if (new_state != XGBE_AN_EVENT)
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ return new_state;
+}
+
+static enum xgbe_an xgbe_phy_an_page_received(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ enum xgbe_an_rx *state;
+ enum xgbe_an new_state;
+
+ state = xgbe_phy_in_kr_mode(phydev) ? &pdata->phy.kr_state
+ : &pdata->phy.kx_state;
+
+ switch (*state) {
+ case XGBE_AN_RX_BPA:
+ new_state = xgbe_phy_an_rx_bpa(phydev, state);
+ break;
+
+ case XGBE_AN_RX_XNP:
+ new_state = xgbe_phy_an_rx_xnp(phydev, state);
+ break;
+
+ default:
+ new_state = XGBE_AN_ERROR;
+ }
+
+ return new_state;
+}
+
+static enum xgbe_an xgbe_phy_an_incompat_link(struct phy_device *phydev)
+{
+ xgbe_phy_switch_mode(phydev);
+
+ return XGBE_AN_START;
+}
+
+static void xgbe_phy_an_state_machine(struct work_struct *work)
+{
+ struct xgbe_prv_data *pdata = container_of(work,
+ struct xgbe_prv_data,
+ phy.an_work);
+ struct phy_device *phydev = pdata->phy.phydev;
+ enum xgbe_an cur_state;
+ unsigned int sleep;
+ unsigned int an_supported = 0;
+
+ while (1) {
+ mutex_lock(&pdata->phy.an_mutex);
+
+ cur_state = pdata->phy.an_state;
+
+ switch (pdata->phy.an_state) {
+ case XGBE_AN_START:
+ an_supported = 0;
+ pdata->phy.an_state = xgbe_phy_an_start(phydev);
+ break;
+
+ case XGBE_AN_EVENT:
+ pdata->phy.an_state = xgbe_phy_an_event(phydev);
+ break;
+
+ case XGBE_AN_PAGE_RECEIVED:
+ an_supported++;
+ pdata->phy.an_state = xgbe_phy_an_page_received(phydev);
+ break;
+
+ case XGBE_AN_INCOMPAT_LINK:
+ pdata->phy.an_state = xgbe_phy_an_incompat_link(phydev);
+ break;
+
+ case XGBE_AN_COMPLETE:
+ netdev_info(phydev->attached_dev, "%s successful\n",
+ an_supported ? "Auto negotiation"
+ : "Parallel detection");
+ /* fall through */
+
+ case XGBE_AN_NO_LINK:
+ case XGBE_AN_EXIT:
+ goto exit_unlock;
+
+ default:
+ pdata->phy.an_state = XGBE_AN_ERROR;
+ }
+
+ if (pdata->phy.an_state == XGBE_AN_ERROR) {
+ netdev_err(phydev->attached_dev,
+ "error during auto-negotiation, state=%u\n",
+ cur_state);
+ goto exit_unlock;
+ }
+
+ sleep = (pdata->phy.an_state == XGBE_AN_EVENT) ? 1 : 0;
+
+ mutex_unlock(&pdata->phy.an_mutex);
+
+ if (sleep)
+ usleep_range(20, 50);
+ }
+
+exit_unlock:
+ pdata->phy.an_result = pdata->phy.an_state;
+ pdata->phy.an_state = XGBE_AN_READY;
+
+ mutex_unlock(&pdata->phy.an_mutex);
+}
+
+static int xgbe_phy_soft_reset(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ unsigned int count, val;
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL1, MDIO_CTRL1_RESET,
+ MDIO_CTRL1_RESET);
+
+ count = 50;
+ do {
+ msleep(20);
+ val = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ } while ((val & MDIO_CTRL1_RESET) && --count);
+
+ if (val & MDIO_CTRL1_RESET)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int xgbe_phy_config_init(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Initialize supported features */
+ phydev->supported = SUPPORTED_Autoneg;
+ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ phydev->supported |= SUPPORTED_Backplane;
+ phydev->supported |= SUPPORTED_10000baseKR_Full |
+ SUPPORTED_10000baseR_FEC;
+ switch (pdata->speed_set) {
+ case XGBE_PHY_SPEEDSET_1000_10000:
+ phydev->supported |= SUPPORTED_1000baseKX_Full;
+ break;
+ case XGBE_PHY_SPEEDSET_2500_10000:
+ phydev->supported |= SUPPORTED_2500baseX_Full;
+ break;
+ }
+ phydev->advertising = phydev->supported;
+
+ /* Turn off and clear interrupts */
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ return 0;
+}
+
+static int xgbe_phy_setup_forced(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Disable auto-negotiation */
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_AN, MDIO_CTRL1, MDIO_AN_CTRL1_ENABLE,
+ 0);
+
+ /* Validate/Set specified speed */
+ switch (phydev->speed) {
+ case SPEED_10000:
+ xgbe_phy_xgmii_mode(phydev);
+ break;
+
+ case SPEED_2500:
+ xgbe_phy_gmii_2500_mode(phydev);
+ break;
+
+ case SPEED_1000:
+ xgbe_phy_gmii_mode(phydev);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Validate duplex mode */
+ if (phydev->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+
+ return 0;
+}
+
+static int xgbe_phy_config_aneg(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ u32 mmd_mask = phydev->c45_ids.devices_in_package;
+
+ if (phydev->autoneg != AUTONEG_ENABLE)
+ return xgbe_phy_setup_forced(phydev);
+
+ /* Make sure we have the AN MMD present */
+ if (!(mmd_mask & MDIO_DEVS_AN))
+ return -EINVAL;
+
+ /* Start/Restart the auto-negotiation state machine */
+ mutex_lock(&pdata->phy.an_mutex);
+ pdata->phy.an_result = XGBE_AN_READY;
+ pdata->phy.an_state = XGBE_AN_START;
+ pdata->phy.kr_state = XGBE_AN_RX_READY;
+ pdata->phy.kx_state = XGBE_AN_RX_READY;
+ mutex_unlock(&pdata->phy.an_mutex);
+
+ queue_work(pdata->phy.an_workqueue, &pdata->phy.an_work);
+
+ return 0;
+}
+
+static int xgbe_phy_aneg_done(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ enum xgbe_an state;
+
+ mutex_lock(&pdata->phy.an_mutex);
+ state = pdata->phy.an_result;
+ mutex_unlock(&pdata->phy.an_mutex);
+
+ return (state == XGBE_AN_COMPLETE);
+}
+
+static int xgbe_phy_update_link(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ enum xgbe_an state;
+ unsigned int check_again, autoneg, val;
+ int ret = 0;
+
+ /* If we're doing auto-negotiation don't report link down */
+ mutex_lock(&pdata->phy.an_mutex);
+ state = pdata->phy.an_state;
+ mutex_unlock(&pdata->phy.an_mutex);
+
+ if (state != XGBE_AN_READY) {
+ phydev->link = 1;
+ return 0;
+ }
+
+ /* Since the device can be in the wrong mode when a link is
+ * (re-)established (cable connected after the interface is
+ * up, etc.), the link status may report no link. If there
+ * is no link, try switching modes and checking the status
+ * again if auto negotiation is enabled.
+ */
+ check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0;
+again:
+ /* Link status is latched low, so read once to clear
+ * and then read again to get current state
+ */
+ val = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ val = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+
+ phydev->link = (val & MDIO_STAT1_LSTATUS) ? 1 : 0;
+
+ if (!phydev->link) {
+ if (check_again) {
+ xgbe_phy_switch_mode(phydev);
+ check_again = 0;
+ goto again;
+ }
+ }
+
+ autoneg = (phydev->link && !pdata->phy.link) ? 1 : 0;
+ pdata->phy.link = phydev->link;
+
+ /* If link is (back) up, re-start auto-negotiation */
+ if (autoneg)
+ ret = xgbe_phy_config_aneg(phydev);
+
+ return ret;
+}
+
+static int xgbe_phy_read_status(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ u32 mmd_mask = phydev->c45_ids.devices_in_package;
+ unsigned int ad_val, lp_val;
+ int ret;
+
+ ret = xgbe_phy_update_link(phydev);
+ if (ret)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_ENABLE) {
+ if (!(mmd_mask & MDIO_DEVS_AN))
+ return -EINVAL;
+
+ if (!xgbe_phy_aneg_done(phydev))
+ return 0;
+
+ /* Compare Advertisement and Link Partner register 1 */
+ ad_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ lp_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
+
+ ad_val &= lp_val;
+ phydev->pause = (ad_val & 0x400) ? 1 : 0;
+ phydev->asym_pause = (ad_val & 0x800) ? 1 : 0;
+
+ /* Compare Advertisement and Link Partner register 2 */
+ ad_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
+ lp_val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
+
+ ad_val &= lp_val;
+ if (ad_val & 0x80) {
+ phydev->speed = SPEED_10000;
+ xgbe_phy_set_mode(phydev, XGBE_SPEED_MODE_KR);
+ } else {
+ switch (pdata->speed_set) {
+ case XGBE_PHY_SPEEDSET_1000_10000:
+ phydev->speed = SPEED_1000;
+ break;
+
+ case XGBE_PHY_SPEEDSET_2500_10000:
+ phydev->speed = SPEED_2500;
+ break;
+ }
+ xgbe_phy_set_mode(phydev, XGBE_SPEED_MODE_KX);
+ }
+
+ phydev->duplex = DUPLEX_FULL;
+ } else {
+ if (xgbe_phy_in_kr_mode(phydev)) {
+ phydev->speed = SPEED_10000;
+ } else {
+ switch (pdata->speed_set) {
+ case XGBE_PHY_SPEEDSET_1000_10000:
+ phydev->speed = SPEED_1000;
+ break;
+
+ case XGBE_PHY_SPEEDSET_2500_10000:
+ phydev->speed = SPEED_2500;
+ break;
+ }
+ }
+ phydev->duplex = DUPLEX_FULL;
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+ }
+
+ return 0;
+}
+
+static int xgbe_phy_suspend(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ mutex_lock(&phydev->lock);
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL1, MDIO_CTRL1_LPOWER,
+ MDIO_CTRL1_LPOWER);
+
+ mutex_unlock(&phydev->lock);
+
+ return 0;
+}
+
+static int xgbe_phy_resume(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ mutex_lock(&phydev->lock);
+
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PCS, MDIO_CTRL1, MDIO_CTRL1_LPOWER,
+ 0);
+
+ mutex_unlock(&phydev->lock);
+
+ return 0;
+}
+
+static int xgbe_phy_probe(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+ char *wq_name;
+
+ if (!pdata)
+ return -EINVAL;
+
+ wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", pdata->pdev->name);
+ if (!wq_name)
+ return -ENOMEM;
+
+ pdata->phy.link = 1;
+
+ mutex_init(&pdata->phy.an_mutex);
+ INIT_WORK(&pdata->phy.an_work, xgbe_phy_an_state_machine);
+ pdata->phy.an_workqueue = create_singlethread_workqueue(wq_name);
+ kfree(wq_name);
+ if (!pdata->phy.an_workqueue)
+ return -ENOMEM;
+
+ pdata->phy.probed = 1;
+
+ return 0;
+}
+
+static void xgbe_phy_remove(struct phy_device *phydev)
+{
+ struct xgbe_prv_data *pdata = phydev->priv;
+
+ /* Stop any in process auto-negotiation */
+ mutex_lock(&pdata->phy.an_mutex);
+ pdata->phy.an_state = XGBE_AN_EXIT;
+ mutex_unlock(&pdata->phy.an_mutex);
+
+ flush_workqueue(pdata->phy.an_workqueue);
+ destroy_workqueue(pdata->phy.an_workqueue);
+}
+
+static int xgbe_phy_match_device(struct phy_device *phydev)
+{
+ return phydev->c45_ids.device_ids[MDIO_MMD_PCS] == XGBE_PHY_ID;
+}
+
+static struct phy_driver xgbe_phy_driver[] = {
+ {
+ .phy_id = XGBE_PHY_ID,
+ .phy_id_mask = XGBE_PHY_MASK,
+ .name = "AMD XGBE PHY",
+ .features = 0,
+ .probe = xgbe_phy_probe,
+ .remove = xgbe_phy_remove,
+ .soft_reset = xgbe_phy_soft_reset,
+ .config_init = xgbe_phy_config_init,
+ .suspend = xgbe_phy_suspend,
+ .resume = xgbe_phy_resume,
+ .config_aneg = xgbe_phy_config_aneg,
+ .aneg_done = xgbe_phy_aneg_done,
+ .read_status = xgbe_phy_read_status,
+ .match_phy_device = xgbe_phy_match_device,
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+int xgbe_phy_register(void)
+{
+ return phy_drivers_register(xgbe_phy_driver,
+ ARRAY_SIZE(xgbe_phy_driver));
+}
+
+void xgbe_phy_unregister(void)
+{
+ phy_drivers_unregister(xgbe_phy_driver,
+ ARRAY_SIZE(xgbe_phy_driver));
+}
+
+static struct mdio_device_id __maybe_unused xgbe_phy_ids[] = {
+ { XGBE_PHY_ID, XGBE_PHY_MASK },
+ { }
+};
+MODULE_DEVICE_TABLE(mdio, xgbe_phy_ids);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 07bf70a..36f8717 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -173,6 +173,11 @@
#define XGBE_DMA_CLOCK "dma_clk"
#define XGBE_PTP_CLOCK "ptp_clk"
+/* Device-tree property names/values */
+#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set"
+#define XGBE_PHY_SPEEDSET_1000_10000 0
+#define XGBE_PHY_SPEEDSET_2500_10000 1
+
/* Timestamp support - values based on 50MHz PTP clock
* 50MHz => 20 nsec
*/
@@ -419,6 +424,48 @@ struct xgbe_mmc_stats {
u64 rxwatchdogerror;
};
+enum xgbe_an {
+ XGBE_AN_READY = 0,
+ XGBE_AN_START,
+ XGBE_AN_EVENT,
+ XGBE_AN_PAGE_RECEIVED,
+ XGBE_AN_INCOMPAT_LINK,
+ XGBE_AN_COMPLETE,
+ XGBE_AN_NO_LINK,
+ XGBE_AN_EXIT,
+ XGBE_AN_ERROR,
+};
+
+enum xgbe_an_rx {
+ XGBE_AN_RX_READY = 0,
+ XGBE_AN_RX_BPA,
+ XGBE_AN_RX_XNP,
+ XGBE_AN_RX_COMPLETE,
+};
+
+enum xgbe_speed_mode {
+ XGBE_SPEED_MODE_KR,
+ XGBE_SPEED_MODE_KX,
+};
+
+struct xgbe_phy {
+ struct phy_device *phydev;
+
+ unsigned int probed;
+
+ /* Maintain link status for re-starting auto-negotiation */
+ unsigned int link;
+
+ /* Auto-negotiation state machine support */
+ struct mutex an_mutex;
+ enum xgbe_an an_result;
+ enum xgbe_an an_state;
+ enum xgbe_an_rx kr_state;
+ enum xgbe_an_rx kx_state;
+ struct work_struct an_work;
+ struct workqueue_struct *an_workqueue;
+};
+
struct xgbe_hw_if {
int (*tx_complete)(struct xgbe_ring_desc *);
@@ -573,6 +620,13 @@ struct xgbe_prv_data {
void __iomem *xgmac_regs; /* XGMAC CSRs */
void __iomem *xpcs_regs; /* XPCS MMD registers */
+ /* SerDes related mmio registers */
+ void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */
+ void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
+ void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
+
+ unsigned int speed_set;
+
/* Overall device lock */
spinlock_t lock;
@@ -631,11 +685,10 @@ struct xgbe_prv_data {
unsigned int rx_pause;
/* MDIO settings */
- struct module *phy_module;
char *mii_bus_id;
struct mii_bus *mii;
int mdio_mmd;
- struct phy_device *phydev;
+ struct xgbe_phy phy;
int default_autoneg;
int default_speed;
@@ -705,6 +758,8 @@ struct ethtool_ops *xgbe_get_ethtool_ops(void);
const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void);
#endif
+int xgbe_phy_register(void);
+void xgbe_phy_unregister(void);
int xgbe_mdio_register(struct xgbe_prv_data *);
void xgbe_mdio_unregister(struct xgbe_prv_data *);
void xgbe_dump_phy_registers(struct xgbe_prv_data *);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 28437ab..60a53bb 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -24,12 +24,6 @@ config AMD_PHY
---help---
Currently supports the am79c874
-config AMD_XGBE_PHY
- tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
- depends on OF
- ---help---
- Currently supports the AMD 10GbE PHY
-
config MARVELL_PHY
tristate "Drivers for Marvell PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index eb3b18b..21813d1 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -33,5 +33,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o
obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
-obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-phy.o
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c
deleted file mode 100644
index f3230ee..0000000
--- a/drivers/net/phy/amd-xgbe-phy.c
+++ /dev/null
@@ -1,1457 +0,0 @@
-/*
- * AMD 10Gb Ethernet PHY driver
- *
- * This file is available to you under your choice of the following two
- * licenses:
- *
- * License 1: GPLv2
- *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
- *
- * This file is free software; you may copy, redistribute and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or (at
- * your option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *
- * License 2: Modified BSD
- *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Advanced Micro Devices, Inc. nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/phy.h>
-#include <linux/mdio.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/uaccess.h>
-
-
-MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION("1.0.0-a");
-MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
-
-#define XGBE_PHY_ID 0x000162d0
-#define XGBE_PHY_MASK 0xfffffff0
-
-#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set"
-
-#define XGBE_AN_INT_CMPLT 0x01
-#define XGBE_AN_INC_LINK 0x02
-#define XGBE_AN_PG_RCV 0x04
-
-#define XNP_MCF_NULL_MESSAGE 0x001
-#define XNP_ACK_PROCESSED (1 << 12)
-#define XNP_MP_FORMATTED (1 << 13)
-#define XNP_NP_EXCHANGE (1 << 15)
-
-#define XGBE_PHY_RATECHANGE_COUNT 500
-
-#ifndef MDIO_PMA_10GBR_PMD_CTRL
-#define MDIO_PMA_10GBR_PMD_CTRL 0x0096
-#endif
-#ifndef MDIO_PMA_10GBR_FEC_CTRL
-#define MDIO_PMA_10GBR_FEC_CTRL 0x00ab
-#endif
-#ifndef MDIO_AN_XNP
-#define MDIO_AN_XNP 0x0016
-#endif
-
-#ifndef MDIO_AN_INTMASK
-#define MDIO_AN_INTMASK 0x8001
-#endif
-#ifndef MDIO_AN_INT
-#define MDIO_AN_INT 0x8002
-#endif
-
-#ifndef MDIO_CTRL1_SPEED1G
-#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
-#endif
-
-/* SerDes integration register offsets */
-#define SIR0_KR_RT_1 0x002c
-#define SIR0_STATUS 0x0040
-#define SIR1_SPEED 0x0000
-
-/* SerDes integration register entry bit positions and sizes */
-#define SIR0_KR_RT_1_RESET_INDEX 11
-#define SIR0_KR_RT_1_RESET_WIDTH 1
-#define SIR0_STATUS_RX_READY_INDEX 0
-#define SIR0_STATUS_RX_READY_WIDTH 1
-#define SIR0_STATUS_TX_READY_INDEX 8
-#define SIR0_STATUS_TX_READY_WIDTH 1
-#define SIR1_SPEED_DATARATE_INDEX 4
-#define SIR1_SPEED_DATARATE_WIDTH 2
-#define SIR1_SPEED_PI_SPD_SEL_INDEX 12
-#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4
-#define SIR1_SPEED_PLLSEL_INDEX 3
-#define SIR1_SPEED_PLLSEL_WIDTH 1
-#define SIR1_SPEED_RATECHANGE_INDEX 6
-#define SIR1_SPEED_RATECHANGE_WIDTH 1
-#define SIR1_SPEED_TXAMP_INDEX 8
-#define SIR1_SPEED_TXAMP_WIDTH 4
-#define SIR1_SPEED_WORDMODE_INDEX 0
-#define SIR1_SPEED_WORDMODE_WIDTH 3
-
-#define SPEED_10000_CDR 0x7
-#define SPEED_10000_PLL 0x1
-#define SPEED_10000_RATE 0x0
-#define SPEED_10000_TXAMP 0xa
-#define SPEED_10000_WORD 0x7
-
-#define SPEED_2500_CDR 0x2
-#define SPEED_2500_PLL 0x0
-#define SPEED_2500_RATE 0x1
-#define SPEED_2500_TXAMP 0xf
-#define SPEED_2500_WORD 0x1
-
-#define SPEED_1000_CDR 0x2
-#define SPEED_1000_PLL 0x0
-#define SPEED_1000_RATE 0x3
-#define SPEED_1000_TXAMP 0xf
-#define SPEED_1000_WORD 0x1
-
-
-/* SerDes RxTx register offsets */
-#define RXTX_REG20 0x0050
-#define RXTX_REG114 0x01c8
-
-/* SerDes RxTx register entry bit positions and sizes */
-#define RXTX_REG20_BLWC_ENA_INDEX 2
-#define RXTX_REG20_BLWC_ENA_WIDTH 1
-#define RXTX_REG114_PQ_REG_INDEX 9
-#define RXTX_REG114_PQ_REG_WIDTH 7
-
-#define RXTX_10000_BLWC 0
-#define RXTX_10000_PQ 0x1e
-
-#define RXTX_2500_BLWC 1
-#define RXTX_2500_PQ 0xa
-
-#define RXTX_1000_BLWC 1
-#define RXTX_1000_PQ 0xa
-
-/* Bit setting and getting macros
- * The get macro will extract the current bit field value from within
- * the variable
- *
- * The set macro will clear the current bit field value within the
- * variable and then set the bit field of the variable to the
- * specified value
- */
-#define GET_BITS(_var, _index, _width) \
- (((_var) >> (_index)) & ((0x1 << (_width)) - 1))
-
-#define SET_BITS(_var, _index, _width, _val) \
-do { \
- (_var) &= ~(((0x1 << (_width)) - 1) << (_index)); \
- (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \
-} while (0)
-
-#define XSIR_GET_BITS(_var, _prefix, _field) \
- GET_BITS((_var), \
- _prefix##_##_field##_INDEX, \
- _prefix##_##_field##_WIDTH)
-
-#define XSIR_SET_BITS(_var, _prefix, _field, _val) \
- SET_BITS((_var), \
- _prefix##_##_field##_INDEX, \
- _prefix##_##_field##_WIDTH, (_val))
-
-/* Macros for reading or writing SerDes integration registers
- * The ioread macros will get bit fields or full values using the
- * register definitions formed using the input names
- *
- * The iowrite macros will set bit fields or full values using the
- * register definitions formed using the input names
- */
-#define XSIR0_IOREAD(_priv, _reg) \
- ioread16((_priv)->sir0_regs + _reg)
-
-#define XSIR0_IOREAD_BITS(_priv, _reg, _field) \
- GET_BITS(XSIR0_IOREAD((_priv), _reg), \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH)
-
-#define XSIR0_IOWRITE(_priv, _reg, _val) \
- iowrite16((_val), (_priv)->sir0_regs + _reg)
-
-#define XSIR0_IOWRITE_BITS(_priv, _reg, _field, _val) \
-do { \
- u16 reg_val = XSIR0_IOREAD((_priv), _reg); \
- SET_BITS(reg_val, \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH, (_val)); \
- XSIR0_IOWRITE((_priv), _reg, reg_val); \
-} while (0)
-
-#define XSIR1_IOREAD(_priv, _reg) \
- ioread16((_priv)->sir1_regs + _reg)
-
-#define XSIR1_IOREAD_BITS(_priv, _reg, _field) \
- GET_BITS(XSIR1_IOREAD((_priv), _reg), \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH)
-
-#define XSIR1_IOWRITE(_priv, _reg, _val) \
- iowrite16((_val), (_priv)->sir1_regs + _reg)
-
-#define XSIR1_IOWRITE_BITS(_priv, _reg, _field, _val) \
-do { \
- u16 reg_val = XSIR1_IOREAD((_priv), _reg); \
- SET_BITS(reg_val, \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH, (_val)); \
- XSIR1_IOWRITE((_priv), _reg, reg_val); \
-} while (0)
-
-
-/* Macros for reading or writing SerDes RxTx registers
- * The ioread macros will get bit fields or full values using the
- * register definitions formed using the input names
- *
- * The iowrite macros will set bit fields or full values using the
- * register definitions formed using the input names
- */
-#define XRXTX_IOREAD(_priv, _reg) \
- ioread16((_priv)->rxtx_regs + _reg)
-
-#define XRXTX_IOREAD_BITS(_priv, _reg, _field) \
- GET_BITS(XRXTX_IOREAD((_priv), _reg), \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH)
-
-#define XRXTX_IOWRITE(_priv, _reg, _val) \
- iowrite16((_val), (_priv)->rxtx_regs + _reg)
-
-#define XRXTX_IOWRITE_BITS(_priv, _reg, _field, _val) \
-do { \
- u16 reg_val = XRXTX_IOREAD((_priv), _reg); \
- SET_BITS(reg_val, \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH, (_val)); \
- XRXTX_IOWRITE((_priv), _reg, reg_val); \
-} while (0)
-
-
-enum amd_xgbe_phy_an {
- AMD_XGBE_AN_READY = 0,
- AMD_XGBE_AN_START,
- AMD_XGBE_AN_EVENT,
- AMD_XGBE_AN_PAGE_RECEIVED,
- AMD_XGBE_AN_INCOMPAT_LINK,
- AMD_XGBE_AN_COMPLETE,
- AMD_XGBE_AN_NO_LINK,
- AMD_XGBE_AN_EXIT,
- AMD_XGBE_AN_ERROR,
-};
-
-enum amd_xgbe_phy_rx {
- AMD_XGBE_RX_READY = 0,
- AMD_XGBE_RX_BPA,
- AMD_XGBE_RX_XNP,
- AMD_XGBE_RX_COMPLETE,
-};
-
-enum amd_xgbe_phy_mode {
- AMD_XGBE_MODE_KR,
- AMD_XGBE_MODE_KX,
-};
-
-enum amd_xgbe_phy_speedset {
- AMD_XGBE_PHY_SPEEDSET_1000_10000,
- AMD_XGBE_PHY_SPEEDSET_2500_10000,
-};
-
-struct amd_xgbe_phy_priv {
- struct platform_device *pdev;
- struct device *dev;
-
- struct phy_device *phydev;
-
- /* SerDes related mmio resources */
- struct resource *rxtx_res;
- struct resource *sir0_res;
- struct resource *sir1_res;
-
- /* SerDes related mmio registers */
- void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */
- void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
- void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
-
- /* Maintain link status for re-starting auto-negotiation */
- unsigned int link;
- enum amd_xgbe_phy_mode mode;
- unsigned int speed_set;
-
- /* Auto-negotiation state machine support */
- struct mutex an_mutex;
- enum amd_xgbe_phy_an an_result;
- enum amd_xgbe_phy_an an_state;
- enum amd_xgbe_phy_rx kr_state;
- enum amd_xgbe_phy_rx kx_state;
- struct work_struct an_work;
- struct workqueue_struct *an_workqueue;
-};
-
-static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (ret < 0)
- return ret;
-
- ret |= 0x02;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
-
- return 0;
-}
-
-static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (ret < 0)
- return ret;
-
- ret &= ~0x02;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
-
- return 0;
-}
-
-static int amd_xgbe_phy_pcs_power_cycle(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret |= MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- usleep_range(75, 100);
-
- ret &= ~MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- return 0;
-}
-
-static void amd_xgbe_phy_serdes_start_ratechange(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
-
- /* Assert Rx and Tx ratechange */
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 1);
-}
-
-static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- unsigned int wait;
- u16 status;
-
- /* Release Rx and Tx ratechange */
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 0);
-
- /* Wait for Rx and Tx ready */
- wait = XGBE_PHY_RATECHANGE_COUNT;
- while (wait--) {
- usleep_range(50, 75);
-
- status = XSIR0_IOREAD(priv, SIR0_STATUS);
- if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
- XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
- return;
- }
-
- netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
- status);
-}
-
-static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Enable KR training */
- ret = amd_xgbe_an_enable_kr_training(phydev);
- if (ret < 0)
- return ret;
-
- /* Set PCS to KR/10G speed */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_PCS_CTRL2_TYPE;
- ret |= MDIO_PCS_CTRL2_10GBR;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_CTRL1_SPEEDSEL;
- ret |= MDIO_CTRL1_SPEED10G;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = amd_xgbe_phy_pcs_power_cycle(phydev);
- if (ret < 0)
- return ret;
-
- /* Set SerDes to 10G speed */
- amd_xgbe_phy_serdes_start_ratechange(phydev);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR);
-
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ);
-
- amd_xgbe_phy_serdes_complete_ratechange(phydev);
-
- priv->mode = AMD_XGBE_MODE_KR;
-
- return 0;
-}
-
-static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Disable KR training */
- ret = amd_xgbe_an_disable_kr_training(phydev);
- if (ret < 0)
- return ret;
-
- /* Set PCS to KX/1G speed */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_PCS_CTRL2_TYPE;
- ret |= MDIO_PCS_CTRL2_10GBX;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_CTRL1_SPEEDSEL;
- ret |= MDIO_CTRL1_SPEED1G;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = amd_xgbe_phy_pcs_power_cycle(phydev);
- if (ret < 0)
- return ret;
-
- /* Set SerDes to 2.5G speed */
- amd_xgbe_phy_serdes_start_ratechange(phydev);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR);
-
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ);
-
- amd_xgbe_phy_serdes_complete_ratechange(phydev);
-
- priv->mode = AMD_XGBE_MODE_KX;
-
- return 0;
-}
-
-static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Disable KR training */
- ret = amd_xgbe_an_disable_kr_training(phydev);
- if (ret < 0)
- return ret;
-
- /* Set PCS to KX/1G speed */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_PCS_CTRL2_TYPE;
- ret |= MDIO_PCS_CTRL2_10GBX;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_CTRL1_SPEEDSEL;
- ret |= MDIO_CTRL1_SPEED1G;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = amd_xgbe_phy_pcs_power_cycle(phydev);
- if (ret < 0)
- return ret;
-
- /* Set SerDes to 1G speed */
- amd_xgbe_phy_serdes_start_ratechange(phydev);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR);
-
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ);
-
- amd_xgbe_phy_serdes_complete_ratechange(phydev);
-
- priv->mode = AMD_XGBE_MODE_KX;
-
- return 0;
-}
-
-static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* If we are in KR switch to KX, and vice-versa */
- if (priv->mode == AMD_XGBE_MODE_KR) {
- if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000)
- ret = amd_xgbe_phy_gmii_mode(phydev);
- else
- ret = amd_xgbe_phy_gmii_2500_mode(phydev);
- } else {
- ret = amd_xgbe_phy_xgmii_mode(phydev);
- }
-
- return ret;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_switch_mode(struct phy_device *phydev)
-{
- int ret;
-
- ret = amd_xgbe_phy_switch_mode(phydev);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- return AMD_XGBE_AN_START;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ad_reg, lp_reg, ret;
-
- *state = AMD_XGBE_RX_COMPLETE;
-
- /* If we're in KX mode then we're done */
- if (priv->mode == AMD_XGBE_MODE_KX)
- return AMD_XGBE_AN_EVENT;
-
- /* Enable/Disable FEC */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- if (ad_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 2);
- if (lp_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
- ret |= 0x01;
- else
- ret &= ~0x01;
-
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret);
-
- /* Start KR training */
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1);
-
- ret |= 0x01;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
-
- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0);
-
- return AMD_XGBE_AN_EVENT;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- u16 msg;
-
- *state = AMD_XGBE_RX_XNP;
-
- msg = XNP_MCF_NULL_MESSAGE;
- msg |= XNP_MP_FORMATTED;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg);
-
- return AMD_XGBE_AN_EVENT;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- unsigned int link_support;
- int ret, ad_reg, lp_reg;
-
- /* Read Base Ability register 2 first */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 1);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- /* Check for a supported mode, otherwise restart in a different one */
- link_support = (priv->mode == AMD_XGBE_MODE_KR) ? 0x80 : 0x20;
- if (!(ret & link_support))
- return amd_xgbe_an_switch_mode(phydev);
-
- /* Check Extended Next Page support */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ad_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
- if (lp_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- return ((ad_reg & XNP_NP_EXCHANGE) || (lp_reg & XNP_NP_EXCHANGE)) ?
- amd_xgbe_an_tx_xnp(phydev, state) :
- amd_xgbe_an_tx_training(phydev, state);
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- int ad_reg, lp_reg;
-
- /* Check Extended Next Page support */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ad_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
- if (lp_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- return ((ad_reg & XNP_NP_EXCHANGE) || (lp_reg & XNP_NP_EXCHANGE)) ?
- amd_xgbe_an_tx_xnp(phydev, state) :
- amd_xgbe_an_tx_training(phydev, state);
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Be sure we aren't looping trying to negotiate */
- if (priv->mode == AMD_XGBE_MODE_KR) {
- if (priv->kr_state != AMD_XGBE_RX_READY)
- return AMD_XGBE_AN_NO_LINK;
- priv->kr_state = AMD_XGBE_RX_BPA;
- } else {
- if (priv->kx_state != AMD_XGBE_RX_READY)
- return AMD_XGBE_AN_NO_LINK;
- priv->kx_state = AMD_XGBE_RX_BPA;
- }
-
- /* Set up Advertisement register 3 first */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- if (phydev->supported & SUPPORTED_10000baseR_FEC)
- ret |= 0xc000;
- else
- ret &= ~0xc000;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret);
-
- /* Set up Advertisement register 2 next */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- if (phydev->supported & SUPPORTED_10000baseKR_Full)
- ret |= 0x80;
- else
- ret &= ~0x80;
-
- if ((phydev->supported & SUPPORTED_1000baseKX_Full) ||
- (phydev->supported & SUPPORTED_2500baseX_Full))
- ret |= 0x20;
- else
- ret &= ~0x20;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret);
-
- /* Set up Advertisement register 1 last */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- if (phydev->supported & SUPPORTED_Pause)
- ret |= 0x400;
- else
- ret &= ~0x400;
-
- if (phydev->supported & SUPPORTED_Asym_Pause)
- ret |= 0x800;
- else
- ret &= ~0x800;
-
- /* We don't intend to perform XNP */
- ret &= ~XNP_NP_EXCHANGE;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret);
-
- /* Enable and start auto-negotiation */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- ret |= MDIO_AN_CTRL1_ENABLE;
- ret |= MDIO_AN_CTRL1_RESTART;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret);
-
- return AMD_XGBE_AN_EVENT;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev)
-{
- enum amd_xgbe_phy_an new_state;
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- new_state = AMD_XGBE_AN_EVENT;
- if (ret & XGBE_AN_PG_RCV)
- new_state = AMD_XGBE_AN_PAGE_RECEIVED;
- else if (ret & XGBE_AN_INC_LINK)
- new_state = AMD_XGBE_AN_INCOMPAT_LINK;
- else if (ret & XGBE_AN_INT_CMPLT)
- new_state = AMD_XGBE_AN_COMPLETE;
-
- if (new_state != AMD_XGBE_AN_EVENT)
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
-
- return new_state;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_rx *state;
- int ret;
-
- state = (priv->mode == AMD_XGBE_MODE_KR) ? &priv->kr_state
- : &priv->kx_state;
-
- switch (*state) {
- case AMD_XGBE_RX_BPA:
- ret = amd_xgbe_an_rx_bpa(phydev, state);
- break;
-
- case AMD_XGBE_RX_XNP:
- ret = amd_xgbe_an_rx_xnp(phydev, state);
- break;
-
- default:
- ret = AMD_XGBE_AN_ERROR;
- }
-
- return ret;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
-{
- return amd_xgbe_an_switch_mode(phydev);
-}
-
-static void amd_xgbe_an_state_machine(struct work_struct *work)
-{
- struct amd_xgbe_phy_priv *priv = container_of(work,
- struct amd_xgbe_phy_priv,
- an_work);
- struct phy_device *phydev = priv->phydev;
- enum amd_xgbe_phy_an cur_state;
- int sleep;
- unsigned int an_supported = 0;
-
- while (1) {
- mutex_lock(&priv->an_mutex);
-
- cur_state = priv->an_state;
-
- switch (priv->an_state) {
- case AMD_XGBE_AN_START:
- priv->an_state = amd_xgbe_an_start(phydev);
- an_supported = 0;
- break;
-
- case AMD_XGBE_AN_EVENT:
- priv->an_state = amd_xgbe_an_event(phydev);
- break;
-
- case AMD_XGBE_AN_PAGE_RECEIVED:
- priv->an_state = amd_xgbe_an_page_received(phydev);
- an_supported++;
- break;
-
- case AMD_XGBE_AN_INCOMPAT_LINK:
- priv->an_state = amd_xgbe_an_incompat_link(phydev);
- break;
-
- case AMD_XGBE_AN_COMPLETE:
- netdev_info(phydev->attached_dev, "%s successful\n",
- an_supported ? "Auto negotiation"
- : "Parallel detection");
- /* fall through */
-
- case AMD_XGBE_AN_NO_LINK:
- case AMD_XGBE_AN_EXIT:
- goto exit_unlock;
-
- default:
- priv->an_state = AMD_XGBE_AN_ERROR;
- }
-
- if (priv->an_state == AMD_XGBE_AN_ERROR) {
- netdev_err(phydev->attached_dev,
- "error during auto-negotiation, state=%u\n",
- cur_state);
- goto exit_unlock;
- }
-
- sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0;
-
- mutex_unlock(&priv->an_mutex);
-
- if (sleep)
- usleep_range(20, 50);
- }
-
-exit_unlock:
- priv->an_result = priv->an_state;
- priv->an_state = AMD_XGBE_AN_READY;
-
- mutex_unlock(&priv->an_mutex);
-}
-
-static int amd_xgbe_phy_soft_reset(struct phy_device *phydev)
-{
- int count, ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret |= MDIO_CTRL1_RESET;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- count = 50;
- do {
- msleep(20);
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
- } while ((ret & MDIO_CTRL1_RESET) && --count);
-
- if (ret & MDIO_CTRL1_RESET)
- return -ETIMEDOUT;
-
- return 0;
-}
-
-static int amd_xgbe_phy_config_init(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
-
- /* Initialize supported features */
- phydev->supported = SUPPORTED_Autoneg;
- phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- phydev->supported |= SUPPORTED_Backplane;
- phydev->supported |= SUPPORTED_10000baseKR_Full |
- SUPPORTED_10000baseR_FEC;
- switch (priv->speed_set) {
- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
- phydev->supported |= SUPPORTED_1000baseKX_Full;
- break;
- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
- phydev->supported |= SUPPORTED_2500baseX_Full;
- break;
- }
- phydev->advertising = phydev->supported;
-
- /* Turn off and clear interrupts */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
-
- return 0;
-}
-
-static int amd_xgbe_phy_setup_forced(struct phy_device *phydev)
-{
- int ret;
-
- /* Disable auto-negotiation */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_AN_CTRL1_ENABLE;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret);
-
- /* Validate/Set specified speed */
- switch (phydev->speed) {
- case SPEED_10000:
- ret = amd_xgbe_phy_xgmii_mode(phydev);
- break;
-
- case SPEED_2500:
- ret = amd_xgbe_phy_gmii_2500_mode(phydev);
- break;
-
- case SPEED_1000:
- ret = amd_xgbe_phy_gmii_mode(phydev);
- break;
-
- default:
- ret = -EINVAL;
- }
-
- if (ret < 0)
- return ret;
-
- /* Validate duplex mode */
- if (phydev->duplex != DUPLEX_FULL)
- return -EINVAL;
-
- phydev->pause = 0;
- phydev->asym_pause = 0;
-
- return 0;
-}
-
-static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- u32 mmd_mask = phydev->c45_ids.devices_in_package;
- int ret;
-
- if (phydev->autoneg != AUTONEG_ENABLE)
- return amd_xgbe_phy_setup_forced(phydev);
-
- /* Make sure we have the AN MMD present */
- if (!(mmd_mask & MDIO_DEVS_AN))
- return -EINVAL;
-
- /* Get the current speed mode */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- /* Start/Restart the auto-negotiation state machine */
- mutex_lock(&priv->an_mutex);
- priv->an_result = AMD_XGBE_AN_READY;
- priv->an_state = AMD_XGBE_AN_START;
- priv->kr_state = AMD_XGBE_RX_READY;
- priv->kx_state = AMD_XGBE_RX_READY;
- mutex_unlock(&priv->an_mutex);
-
- queue_work(priv->an_workqueue, &priv->an_work);
-
- return 0;
-}
-
-static int amd_xgbe_phy_aneg_done(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_an state;
-
- mutex_lock(&priv->an_mutex);
- state = priv->an_result;
- mutex_unlock(&priv->an_mutex);
-
- return (state == AMD_XGBE_AN_COMPLETE);
-}
-
-static int amd_xgbe_phy_update_link(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_an state;
- unsigned int check_again, autoneg;
- int ret;
-
- /* If we're doing auto-negotiation don't report link down */
- mutex_lock(&priv->an_mutex);
- state = priv->an_state;
- mutex_unlock(&priv->an_mutex);
-
- if (state != AMD_XGBE_AN_READY) {
- phydev->link = 1;
- return 0;
- }
-
- /* Since the device can be in the wrong mode when a link is
- * (re-)established (cable connected after the interface is
- * up, etc.), the link status may report no link. If there
- * is no link, try switching modes and checking the status
- * again if auto negotiation is enabled.
- */
- check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0;
-again:
- /* Link status is latched low, so read once to clear
- * and then read again to get current state
- */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
- if (ret < 0)
- return ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
- if (ret < 0)
- return ret;
-
- phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0;
-
- if (!phydev->link) {
- if (check_again) {
- ret = amd_xgbe_phy_switch_mode(phydev);
- if (ret < 0)
- return ret;
- check_again = 0;
- goto again;
- }
- }
-
- autoneg = (phydev->link && !priv->link) ? 1 : 0;
- priv->link = phydev->link;
- if (autoneg) {
- /* Link is (back) up, re-start auto-negotiation */
- ret = amd_xgbe_phy_config_aneg(phydev);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int amd_xgbe_phy_read_status(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- u32 mmd_mask = phydev->c45_ids.devices_in_package;
- int ret, mode, ad_ret, lp_ret;
-
- ret = amd_xgbe_phy_update_link(phydev);
- if (ret)
- return ret;
-
- mode = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (mode < 0)
- return mode;
- mode &= MDIO_PCS_CTRL2_TYPE;
-
- if (phydev->autoneg == AUTONEG_ENABLE) {
- if (!(mmd_mask & MDIO_DEVS_AN))
- return -EINVAL;
-
- if (!amd_xgbe_phy_aneg_done(phydev))
- return 0;
-
- /* Compare Advertisement and Link Partner register 1 */
- ad_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ad_ret < 0)
- return ad_ret;
- lp_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
- if (lp_ret < 0)
- return lp_ret;
-
- ad_ret &= lp_ret;
- phydev->pause = (ad_ret & 0x400) ? 1 : 0;
- phydev->asym_pause = (ad_ret & 0x800) ? 1 : 0;
-
- /* Compare Advertisement and Link Partner register 2 */
- ad_ret = phy_read_mmd(phydev, MDIO_MMD_AN,
- MDIO_AN_ADVERTISE + 1);
- if (ad_ret < 0)
- return ad_ret;
- lp_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 1);
- if (lp_ret < 0)
- return lp_ret;
-
- ad_ret &= lp_ret;
- if (ad_ret & 0x80) {
- phydev->speed = SPEED_10000;
- if (mode != MDIO_PCS_CTRL2_10GBR) {
- ret = amd_xgbe_phy_xgmii_mode(phydev);
- if (ret < 0)
- return ret;
- }
- } else {
- int (*mode_fcn)(struct phy_device *);
-
- if (priv->speed_set ==
- AMD_XGBE_PHY_SPEEDSET_1000_10000) {
- phydev->speed = SPEED_1000;
- mode_fcn = amd_xgbe_phy_gmii_mode;
- } else {
- phydev->speed = SPEED_2500;
- mode_fcn = amd_xgbe_phy_gmii_2500_mode;
- }
-
- if (mode == MDIO_PCS_CTRL2_10GBR) {
- ret = mode_fcn(phydev);
- if (ret < 0)
- return ret;
- }
- }
-
- phydev->duplex = DUPLEX_FULL;
- } else {
- if (mode == MDIO_PCS_CTRL2_10GBR) {
- phydev->speed = SPEED_10000;
- } else {
- if (priv->speed_set ==
- AMD_XGBE_PHY_SPEEDSET_1000_10000)
- phydev->speed = SPEED_1000;
- else
- phydev->speed = SPEED_2500;
- }
- phydev->duplex = DUPLEX_FULL;
- phydev->pause = 0;
- phydev->asym_pause = 0;
- }
-
- return 0;
-}
-
-static int amd_xgbe_phy_suspend(struct phy_device *phydev)
-{
- int ret;
-
- mutex_lock(&phydev->lock);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- goto unlock;
-
- ret |= MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = 0;
-
-unlock:
- mutex_unlock(&phydev->lock);
-
- return ret;
-}
-
-static int amd_xgbe_phy_resume(struct phy_device *phydev)
-{
- int ret;
-
- mutex_lock(&phydev->lock);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- goto unlock;
-
- ret &= ~MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = 0;
-
-unlock:
- mutex_unlock(&phydev->lock);
-
- return ret;
-}
-
-static int amd_xgbe_phy_probe(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv;
- struct platform_device *pdev;
- struct device *dev;
- char *wq_name;
- const __be32 *property;
- unsigned int speed_set;
- int ret;
-
- if (!phydev->dev.of_node)
- return -EINVAL;
-
- pdev = of_find_device_by_node(phydev->dev.of_node);
- if (!pdev)
- return -EINVAL;
- dev = &pdev->dev;
-
- wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name);
- if (!wq_name) {
- ret = -ENOMEM;
- goto err_pdev;
- }
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto err_name;
- }
-
- priv->pdev = pdev;
- priv->dev = dev;
- priv->phydev = phydev;
-
- /* Get the device mmio areas */
- priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res);
- if (IS_ERR(priv->rxtx_regs)) {
- dev_err(dev, "rxtx ioremap failed\n");
- ret = PTR_ERR(priv->rxtx_regs);
- goto err_priv;
- }
-
- priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res);
- if (IS_ERR(priv->sir0_regs)) {
- dev_err(dev, "sir0 ioremap failed\n");
- ret = PTR_ERR(priv->sir0_regs);
- goto err_rxtx;
- }
-
- priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res);
- if (IS_ERR(priv->sir1_regs)) {
- dev_err(dev, "sir1 ioremap failed\n");
- ret = PTR_ERR(priv->sir1_regs);
- goto err_sir0;
- }
-
- /* Get the device speed set property */
- speed_set = 0;
- property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY,
- NULL);
- if (property)
- speed_set = be32_to_cpu(*property);
-
- switch (speed_set) {
- case 0:
- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000;
- break;
- case 1:
- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000;
- break;
- default:
- dev_err(dev, "invalid amd,speed-set property\n");
- ret = -EINVAL;
- goto err_sir1;
- }
-
- priv->link = 1;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- goto err_sir1;
- if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
- priv->mode = AMD_XGBE_MODE_KR;
- else
- priv->mode = AMD_XGBE_MODE_KX;
-
- mutex_init(&priv->an_mutex);
- INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
- priv->an_workqueue = create_singlethread_workqueue(wq_name);
- if (!priv->an_workqueue) {
- ret = -ENOMEM;
- goto err_sir1;
- }
-
- phydev->priv = priv;
-
- kfree(wq_name);
- of_dev_put(pdev);
-
- return 0;
-
-err_sir1:
- devm_iounmap(dev, priv->sir1_regs);
- devm_release_mem_region(dev, priv->sir1_res->start,
- resource_size(priv->sir1_res));
-
-err_sir0:
- devm_iounmap(dev, priv->sir0_regs);
- devm_release_mem_region(dev, priv->sir0_res->start,
- resource_size(priv->sir0_res));
-
-err_rxtx:
- devm_iounmap(dev, priv->rxtx_regs);
- devm_release_mem_region(dev, priv->rxtx_res->start,
- resource_size(priv->rxtx_res));
-
-err_priv:
- devm_kfree(dev, priv);
-
-err_name:
- kfree(wq_name);
-
-err_pdev:
- of_dev_put(pdev);
-
- return ret;
-}
-
-static void amd_xgbe_phy_remove(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- struct device *dev = priv->dev;
-
- /* Stop any in process auto-negotiation */
- mutex_lock(&priv->an_mutex);
- priv->an_state = AMD_XGBE_AN_EXIT;
- mutex_unlock(&priv->an_mutex);
-
- flush_workqueue(priv->an_workqueue);
- destroy_workqueue(priv->an_workqueue);
-
- /* Release resources */
- devm_iounmap(dev, priv->sir1_regs);
- devm_release_mem_region(dev, priv->sir1_res->start,
- resource_size(priv->sir1_res));
-
- devm_iounmap(dev, priv->sir0_regs);
- devm_release_mem_region(dev, priv->sir0_res->start,
- resource_size(priv->sir0_res));
-
- devm_iounmap(dev, priv->rxtx_regs);
- devm_release_mem_region(dev, priv->rxtx_res->start,
- resource_size(priv->rxtx_res));
-
- devm_kfree(dev, priv);
-}
-
-static int amd_xgbe_match_phy_device(struct phy_device *phydev)
-{
- return phydev->c45_ids.device_ids[MDIO_MMD_PCS] == XGBE_PHY_ID;
-}
-
-static struct phy_driver amd_xgbe_phy_driver[] = {
- {
- .phy_id = XGBE_PHY_ID,
- .phy_id_mask = XGBE_PHY_MASK,
- .name = "AMD XGBE PHY",
- .features = 0,
- .probe = amd_xgbe_phy_probe,
- .remove = amd_xgbe_phy_remove,
- .soft_reset = amd_xgbe_phy_soft_reset,
- .config_init = amd_xgbe_phy_config_init,
- .suspend = amd_xgbe_phy_suspend,
- .resume = amd_xgbe_phy_resume,
- .config_aneg = amd_xgbe_phy_config_aneg,
- .aneg_done = amd_xgbe_phy_aneg_done,
- .read_status = amd_xgbe_phy_read_status,
- .match_phy_device = amd_xgbe_match_phy_device,
- .driver = {
- .owner = THIS_MODULE,
- },
- },
-};
-
-static int __init amd_xgbe_phy_init(void)
-{
- return phy_drivers_register(amd_xgbe_phy_driver,
- ARRAY_SIZE(amd_xgbe_phy_driver));
-}
-
-static void __exit amd_xgbe_phy_exit(void)
-{
- phy_drivers_unregister(amd_xgbe_phy_driver,
- ARRAY_SIZE(amd_xgbe_phy_driver));
-}
-
-module_init(amd_xgbe_phy_init);
-module_exit(amd_xgbe_phy_exit);
-
-static struct mdio_device_id __maybe_unused amd_xgbe_phy_ids[] = {
- { XGBE_PHY_ID, XGBE_PHY_MASK },
- { }
-};
-MODULE_DEVICE_TABLE(mdio, amd_xgbe_phy_ids);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next v1 2/3] amd-xgbe: Move the phy device resources into network device
2014-08-29 15:21 [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 Tom Lendacky
2014-08-29 15:21 ` [PATCH net-next v1 1/3] amd-xgbe: Move phy driver support into the network driver Tom Lendacky
@ 2014-08-29 15:22 ` Tom Lendacky
2014-08-29 15:22 ` [PATCH net-next v1 3/3] amd-xgbe: Enhance auto-negotiation parallel detection Tom Lendacky
2014-09-02 3:31 ` [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 David Miller
3 siblings, 0 replies; 6+ messages in thread
From: Tom Lendacky @ 2014-08-29 15:22 UTC (permalink / raw)
To: netdev; +Cc: davem
As the second step of moving the phy driver into the network driver,
move the phy device resources and settings into the network device.
Creating a new compatible id string for this format allows for backward
compatibility with old device trees.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../devicetree/bindings/net/amd-xgbe-phy.txt | 23 --------
Documentation/devicetree/bindings/net/amd-xgbe.txt | 18 ++++--
drivers/net/ethernet/amd/xgbe/xgbe-main.c | 60 ++++++++++++++------
drivers/net/ethernet/amd/xgbe/xgbe-phy.c | 14 ++---
drivers/net/ethernet/amd/xgbe/xgbe.h | 13 +++-
5 files changed, 73 insertions(+), 55 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
diff --git a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
deleted file mode 100644
index 42409bf..0000000
--- a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-* AMD 10GbE PHY driver (amd-xgbe-phy)
-
-Required properties:
-- compatible: Should be "amd,xgbe-phy-seattle-v1a" and
- "ethernet-phy-ieee802.3-c45"
-- reg: Address and length of the register sets for the device
- - SerDes Rx/Tx registers
- - SerDes integration registers (1/2)
- - SerDes integration registers (2/2)
-
-Optional properties:
-- amd,speed-set: Speed capabilities of the device
- 0 - 1GbE and 10GbE (default)
- 1 - 2.5GbE and 10GbE
-
-Example:
- xgbe_phy@e1240800 {
- compatible = "amd,xgbe-phy-seattle-v1a", "ethernet-phy-ieee802.3-c45";
- reg = <0 0xe1240800 0 0x00400>,
- <0 0xe1250000 0 0x00060>,
- <0 0xe1250080 0 0x00004>;
- amd,speed-set = <0>;
- };
diff --git a/Documentation/devicetree/bindings/net/amd-xgbe.txt b/Documentation/devicetree/bindings/net/amd-xgbe.txt
index 41354f7..259482c 100644
--- a/Documentation/devicetree/bindings/net/amd-xgbe.txt
+++ b/Documentation/devicetree/bindings/net/amd-xgbe.txt
@@ -1,10 +1,13 @@
* AMD 10GbE driver (amd-xgbe)
Required properties:
-- compatible: Should be "amd,xgbe-seattle-v1a"
+- compatible: Should be "amd,xgbe-seattle-v1b"
- reg: Address and length of the register sets for the device
- MAC registers
- PCS registers
+ - SerDes Rx/Tx registers
+ - SerDes integration registers (1/2)
+ - SerDes integration registers (2/2)
- interrupt-parent: Should be the phandle for the interrupt controller
that services interrupts for this device
- interrupts: Should contain the amd-xgbe interrupt
@@ -16,24 +19,29 @@ Required properties:
- clock-names: Should be the names of the clocks
- "dma_clk" for the DMA clock
- "ptp_clk" for the PTP clock
-- phy-handle: See ethernet.txt file in the same directory
- phy-mode: See ethernet.txt file in the same directory
Optional properties:
- mac-address: mac address to be assigned to the device. Can be overridden
by UEFI.
+- amd,speed-set: available network speeds
+ 0 - 1GbE and 10GbE
+ 1 - 2.5GbE and 10GbE
- dma-coherent: Present if dma operations are coherent
Example:
xgbe@e0700000 {
- compatible = "amd,xgbe-seattle-v1a";
+ compatible = "amd,xgbe-seattle-v1b";
reg = <0 0xe0700000 0 0x80000>,
- <0 0xe0780000 0 0x80000>;
+ <0 0xe0780000 0 0x80000>,
+ <0 0xe1240800 0 0x00400>,
+ <0 0xe1250000 0 0x00060>,
+ <0 0xe1250080 0 0x00004>;
interrupt-parent = <&gic>;
interrupts = <0 325 4>;
clocks = <&xgbe_dma_clk>, <&xgbe_ptp_clk>;
clock-names = "dma_clk", "ptp_clk";
- phy-handle = <&phy>;
phy-mode = "xgmii";
+ amd,speed-set = <0>;
mac-address = [ 02 a1 a2 a3 a4 a5 ];
};
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index f9ffbfc..7382525 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -136,6 +136,8 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(XGBE_DRV_VERSION);
MODULE_DESCRIPTION(XGBE_DRV_DESC);
+static const struct of_device_id xgbe_of_match[];
+
static struct xgbe_channel *xgbe_alloc_rings(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel_mem, *channel;
@@ -224,12 +226,14 @@ static int xgbe_probe(struct platform_device *pdev)
struct xgbe_hw_if *hw_if;
struct xgbe_desc_if *desc_if;
struct net_device *netdev;
+ const struct of_device_id *of_dev;
struct device *dev = &pdev->dev;
struct device_node *phy_node;
struct platform_device *phy_pdev;
struct resource *res;
const __be32 *property;
const u8 *mac_addr;
+ unsigned int mem_resource;
int ret;
DBGPR("--> xgbe_probe\n");
@@ -252,19 +256,34 @@ static int xgbe_probe(struct platform_device *pdev)
mutex_init(&pdata->xpcs_mutex);
spin_lock_init(&pdata->tstamp_lock);
- /* Obtain a reference the phy device */
- phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
- if (!phy_node) {
- dev_err(dev, "unable to parse phy-handle\n");
- ret = -EINVAL;
+ of_dev = of_match_device(xgbe_of_match, dev);
+ if (!of_dev) {
+ ret = -ENODEV;
goto err_put;
}
+ pdata->drv_level = (enum xgbe_drv_level)of_dev->data;
+
+ if (pdata->drv_level == XGBE_DRV_LEVEL_V1A) {
+ /* Obtain a reference the phy device */
+ phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
+ if (!phy_node) {
+ dev_err(dev, "unable to parse phy-handle\n");
+ ret = -EINVAL;
+ goto err_put;
+ }
- phy_pdev = of_find_device_by_node(phy_node);
- if (!phy_pdev) {
- dev_err(dev, "unable to locate phy device\n");
- ret = -EINVAL;
- goto err_io;
+ phy_pdev = of_find_device_by_node(phy_node);
+ if (!phy_pdev) {
+ dev_err(dev, "unable to locate phy device\n");
+ ret = -EINVAL;
+ goto err_io;
+ }
+
+ mem_resource = 0;
+ } else {
+ phy_node = of_node_get(dev->of_node);
+ phy_pdev = pdev;
+ mem_resource = 2;
}
/* Set and validate the number of descriptors for a ring */
@@ -321,7 +340,7 @@ static int xgbe_probe(struct platform_device *pdev)
DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
/* Obtain the mmio areas for the phy device */
- res = platform_get_resource(phy_pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, mem_resource++);
pdata->rxtx_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->rxtx_regs)) {
dev_err(dev, "rxtx ioremap failed\n");
@@ -330,7 +349,7 @@ static int xgbe_probe(struct platform_device *pdev)
}
DBGPR(" rxtx_regs = %p\n", pdata->rxtx_regs);
- res = platform_get_resource(phy_pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, mem_resource++);
pdata->sir0_regs = devm_ioremap_nocache(dev, res->start,
resource_size(res));
if (IS_ERR(pdata->sir0_regs)) {
@@ -340,7 +359,7 @@ static int xgbe_probe(struct platform_device *pdev)
}
DBGPR(" sir0_regs = %p\n", pdata->sir0_regs);
- res = platform_get_resource(phy_pdev, IORESOURCE_MEM, 2);
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, mem_resource++);
pdata->sir1_regs = devm_ioremap_nocache(dev, res->start,
resource_size(res));
if (IS_ERR(pdata->sir1_regs)) {
@@ -351,13 +370,13 @@ static int xgbe_probe(struct platform_device *pdev)
DBGPR(" sir1_regs = %p\n", pdata->sir1_regs);
/* Get the device speed set property */
- property = of_get_property(phy_node, XGBE_PHY_SPEEDSET_PROPERTY, NULL);
+ property = of_get_property(phy_node, XGBE_SPEEDSET_PROPERTY, NULL);
if (property)
pdata->speed_set = be32_to_cpu(*property);
switch (pdata->speed_set) {
- case XGBE_PHY_SPEEDSET_1000_10000:
- case XGBE_PHY_SPEEDSET_2500_10000:
+ case XGBE_SPEEDSET_1000_10000:
+ case XGBE_SPEEDSET_2500_10000:
break;
default:
dev_err(dev, "invalid amd,speed-set property\n");
@@ -604,7 +623,14 @@ static int xgbe_resume(struct device *dev)
#endif /* CONFIG_PM */
static const struct of_device_id xgbe_of_match[] = {
- { .compatible = "amd,xgbe-seattle-v1a", },
+ {
+ .compatible = "amd,xgbe-seattle-v1a",
+ .data = (void *)XGBE_DRV_LEVEL_V1A,
+ },
+ {
+ .compatible = "amd,xgbe-seattle-v1b",
+ .data = (void *)XGBE_DRV_LEVEL_V1B,
+ },
{},
};
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
index 7aca21d..d072201 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
@@ -469,7 +469,7 @@ static void xgbe_phy_switch_mode(struct phy_device *phydev)
/* If we are in KR switch to KX, and vice-versa */
if (xgbe_phy_in_kr_mode(phydev)) {
- if (pdata->speed_set == XGBE_PHY_SPEEDSET_1000_10000)
+ if (pdata->speed_set == XGBE_SPEEDSET_1000_10000)
xgbe_phy_gmii_mode(phydev);
else
xgbe_phy_gmii_2500_mode(phydev);
@@ -805,10 +805,10 @@ static int xgbe_phy_config_init(struct phy_device *phydev)
phydev->supported |= SUPPORTED_10000baseKR_Full |
SUPPORTED_10000baseR_FEC;
switch (pdata->speed_set) {
- case XGBE_PHY_SPEEDSET_1000_10000:
+ case XGBE_SPEEDSET_1000_10000:
phydev->supported |= SUPPORTED_1000baseKX_Full;
break;
- case XGBE_PHY_SPEEDSET_2500_10000:
+ case XGBE_SPEEDSET_2500_10000:
phydev->supported |= SUPPORTED_2500baseX_Full;
break;
}
@@ -981,11 +981,11 @@ static int xgbe_phy_read_status(struct phy_device *phydev)
xgbe_phy_set_mode(phydev, XGBE_SPEED_MODE_KR);
} else {
switch (pdata->speed_set) {
- case XGBE_PHY_SPEEDSET_1000_10000:
+ case XGBE_SPEEDSET_1000_10000:
phydev->speed = SPEED_1000;
break;
- case XGBE_PHY_SPEEDSET_2500_10000:
+ case XGBE_SPEEDSET_2500_10000:
phydev->speed = SPEED_2500;
break;
}
@@ -998,11 +998,11 @@ static int xgbe_phy_read_status(struct phy_device *phydev)
phydev->speed = SPEED_10000;
} else {
switch (pdata->speed_set) {
- case XGBE_PHY_SPEEDSET_1000_10000:
+ case XGBE_SPEEDSET_1000_10000:
phydev->speed = SPEED_1000;
break;
- case XGBE_PHY_SPEEDSET_2500_10000:
+ case XGBE_SPEEDSET_2500_10000:
phydev->speed = SPEED_2500;
break;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 36f8717..2d057cf 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -174,9 +174,9 @@
#define XGBE_PTP_CLOCK "ptp_clk"
/* Device-tree property names/values */
-#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set"
-#define XGBE_PHY_SPEEDSET_1000_10000 0
-#define XGBE_PHY_SPEEDSET_2500_10000 1
+#define XGBE_SPEEDSET_PROPERTY "amd,speed-set"
+#define XGBE_SPEEDSET_1000_10000 0
+#define XGBE_SPEEDSET_2500_10000 1
/* Timestamp support - values based on 50MHz PTP clock
* 50MHz => 20 nsec
@@ -611,11 +611,18 @@ struct xgbe_hw_features {
unsigned int aux_snap_num; /* Number of Aux snapshot inputs */
};
+enum xgbe_drv_level {
+ XGBE_DRV_LEVEL_V1A = 0,
+ XGBE_DRV_LEVEL_V1B,
+};
+
struct xgbe_prv_data {
struct net_device *netdev;
struct platform_device *pdev;
struct device *dev;
+ enum xgbe_drv_level drv_level;
+
/* XGMAC/XPCS related mmio registers */
void __iomem *xgmac_regs; /* XGMAC CSRs */
void __iomem *xpcs_regs; /* XPCS MMD registers */
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next v1 3/3] amd-xgbe: Enhance auto-negotiation parallel detection
2014-08-29 15:21 [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 Tom Lendacky
2014-08-29 15:21 ` [PATCH net-next v1 1/3] amd-xgbe: Move phy driver support into the network driver Tom Lendacky
2014-08-29 15:22 ` [PATCH net-next v1 2/3] amd-xgbe: Move the phy device resources into network device Tom Lendacky
@ 2014-08-29 15:22 ` Tom Lendacky
2014-09-02 3:31 ` [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 David Miller
3 siblings, 0 replies; 6+ messages in thread
From: Tom Lendacky @ 2014-08-29 15:22 UTC (permalink / raw)
To: netdev; +Cc: davem
Add support for parallel detection during auto negotiation while in
KR speed mode. Additionally, don't use auto negotiation registers
to determine state if parallel detection was used.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-phy.c | 19 ++++++++++++++++++-
drivers/net/ethernet/amd/xgbe/xgbe.h | 1 +
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
index d072201..d95c2a8 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy.c
@@ -108,6 +108,10 @@
#define MDIO_AN_INT 0x8002
#endif
+#ifndef MDIO_AN_KR_CTRL
+#define MDIO_AN_KR_CTRL 0x8003
+#endif
+
#ifndef MDIO_CTRL1_SPEED1G
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
#endif
@@ -120,6 +124,10 @@
#define MDIO_PMA_10GBR_KR_TRAIN_ENABLE 0x02
#endif
+#ifndef MDIO_KR_CTRL_PDETECT
+#define MDIO_KR_CTRL_PDETECT 1
+#endif
+
/* SerDes integration register offsets */
#define SIR0_KR_RT_1 0x002c
#define SIR0_STATUS 0x0040
@@ -642,6 +650,9 @@ static enum xgbe_an xgbe_phy_an_start(struct phy_device *phydev)
/* Enable and start auto-negotiation */
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ XMDIO_WRITE_BITS(pdata, MDIO_MMD_AN, MDIO_AN_KR_CTRL,
+ MDIO_KR_CTRL_PDETECT, MDIO_KR_CTRL_PDETECT);
+
val = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
val |= MDIO_AN_CTRL1_ENABLE;
val |= MDIO_AN_CTRL1_RESTART;
@@ -714,6 +725,9 @@ static void xgbe_phy_an_state_machine(struct work_struct *work)
unsigned int sleep;
unsigned int an_supported = 0;
+ /* Start in KX mode */
+ xgbe_phy_set_mode(phydev, XGBE_SPEED_MODE_KX);
+
while (1) {
mutex_lock(&pdata->phy.an_mutex);
@@ -722,6 +736,7 @@ static void xgbe_phy_an_state_machine(struct work_struct *work)
switch (pdata->phy.an_state) {
case XGBE_AN_START:
an_supported = 0;
+ pdata->phy.parallel_detect = 0;
pdata->phy.an_state = xgbe_phy_an_start(phydev);
break;
@@ -739,6 +754,7 @@ static void xgbe_phy_an_state_machine(struct work_struct *work)
break;
case XGBE_AN_COMPLETE:
+ pdata->phy.parallel_detect = an_supported ? 0 : 1;
netdev_info(phydev->attached_dev, "%s successful\n",
an_supported ? "Auto negotiation"
: "Parallel detection");
@@ -956,7 +972,8 @@ static int xgbe_phy_read_status(struct phy_device *phydev)
if (ret)
return ret;
- if (phydev->autoneg == AUTONEG_ENABLE) {
+ if ((phydev->autoneg == AUTONEG_ENABLE) &&
+ !pdata->phy.parallel_detect) {
if (!(mmd_mask & MDIO_DEVS_AN))
return -EINVAL;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 2d057cf..a964266 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -464,6 +464,7 @@ struct xgbe_phy {
enum xgbe_an_rx kx_state;
struct work_struct an_work;
struct workqueue_struct *an_workqueue;
+ unsigned int parallel_detect;
};
struct xgbe_hw_if {
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29
2014-08-29 15:21 [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 Tom Lendacky
` (2 preceding siblings ...)
2014-08-29 15:22 ` [PATCH net-next v1 3/3] amd-xgbe: Enhance auto-negotiation parallel detection Tom Lendacky
@ 2014-09-02 3:31 ` David Miller
2014-09-02 19:55 ` Tom Lendacky
3 siblings, 1 reply; 6+ messages in thread
From: David Miller @ 2014-09-02 3:31 UTC (permalink / raw)
To: thomas.lendacky; +Cc: netdev
From: Tom Lendacky <thomas.lendacky@amd.com>
Date: Fri, 29 Aug 2014 10:21:48 -0500
> The amd-xgbe-phy phylib driver support is integral to the amd-xgbe
> driver and isn't meant to be used by other devices. For this reason
> it is being removed from the driver/net/phy directory and integrated
> into the amd-xgbe driver.
I see no real reason to do this.
Keeping it in the phylib layer forces you to deal with the abstractions
and therefore keeps you from bypassing the phylib API and performing
layer violations.
Please just keep the PHY driver where it is and add your new features
there.
Thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29
2014-09-02 3:31 ` [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 David Miller
@ 2014-09-02 19:55 ` Tom Lendacky
0 siblings, 0 replies; 6+ messages in thread
From: Tom Lendacky @ 2014-09-02 19:55 UTC (permalink / raw)
To: David Miller; +Cc: netdev
On 09/01/2014 10:31 PM, David Miller wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Date: Fri, 29 Aug 2014 10:21:48 -0500
>
>> The amd-xgbe-phy phylib driver support is integral to the amd-xgbe
>> driver and isn't meant to be used by other devices. For this reason
>> it is being removed from the driver/net/phy directory and integrated
>> into the amd-xgbe driver.
>
> I see no real reason to do this.
>
> Keeping it in the phylib layer forces you to deal with the abstractions
> and therefore keeps you from bypassing the phylib API and performing
> layer violations.
>
> Please just keep the PHY driver where it is and add your new features
> there.
Ok, understood. I'll drop this patch series. Any future changes or
enhancements will apply against the established file locations.
Thanks,
Tom
>
> Thanks.
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-09-02 19:56 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-29 15:21 [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 Tom Lendacky
2014-08-29 15:21 ` [PATCH net-next v1 1/3] amd-xgbe: Move phy driver support into the network driver Tom Lendacky
2014-08-29 15:22 ` [PATCH net-next v1 2/3] amd-xgbe: Move the phy device resources into network device Tom Lendacky
2014-08-29 15:22 ` [PATCH net-next v1 3/3] amd-xgbe: Enhance auto-negotiation parallel detection Tom Lendacky
2014-09-02 3:31 ` [PATCH net-next v1 0/3] amd-xgbe: AMD XGBE driver updates 2014-08-29 David Miller
2014-09-02 19:55 ` Tom Lendacky
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).