net: txgbe: Implement phylink pcs
Register MDIO bus for PCS layer to use Synopsys designware XPCS, support 10GBASE-R interface to the controller. Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
af8de1e307
commit
854cace613
|
@ -49,6 +49,7 @@ config TXGBE
|
|||
select SFP
|
||||
select GPIOLIB
|
||||
select GPIOLIB_IRQCHIP
|
||||
select PCS_XPCS
|
||||
select LIBWX
|
||||
help
|
||||
This driver supports Wangxun(R) 10GbE PCI Express family of
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/pcs/pcs-xpcs.h>
|
||||
|
||||
#include "../libwx/wx_type.h"
|
||||
#include "../libwx/wx_hw.h"
|
||||
|
@ -77,6 +78,81 @@ static int txgbe_swnodes_register(struct txgbe *txgbe)
|
|||
return software_node_register_node_group(nodes->group);
|
||||
}
|
||||
|
||||
static int txgbe_pcs_read(struct mii_bus *bus, int addr, int devnum, int regnum)
|
||||
{
|
||||
struct wx *wx = bus->priv;
|
||||
u32 offset, val;
|
||||
|
||||
if (addr)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
offset = devnum << 16 | regnum;
|
||||
|
||||
/* Set the LAN port indicator to IDA_ADDR */
|
||||
wr32(wx, TXGBE_XPCS_IDA_ADDR, offset);
|
||||
|
||||
/* Read the data from IDA_DATA register */
|
||||
val = rd32(wx, TXGBE_XPCS_IDA_DATA);
|
||||
|
||||
return (u16)val;
|
||||
}
|
||||
|
||||
static int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val)
|
||||
{
|
||||
struct wx *wx = bus->priv;
|
||||
u32 offset;
|
||||
|
||||
if (addr)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
offset = devnum << 16 | regnum;
|
||||
|
||||
/* Set the LAN port indicator to IDA_ADDR */
|
||||
wr32(wx, TXGBE_XPCS_IDA_ADDR, offset);
|
||||
|
||||
/* Write the data to IDA_DATA register */
|
||||
wr32(wx, TXGBE_XPCS_IDA_DATA, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
|
||||
{
|
||||
struct mii_bus *mii_bus;
|
||||
struct dw_xpcs *xpcs;
|
||||
struct pci_dev *pdev;
|
||||
struct wx *wx;
|
||||
int ret = 0;
|
||||
|
||||
wx = txgbe->wx;
|
||||
pdev = wx->pdev;
|
||||
|
||||
mii_bus = devm_mdiobus_alloc(&pdev->dev);
|
||||
if (!mii_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
mii_bus->name = "txgbe_pcs_mdio_bus";
|
||||
mii_bus->read_c45 = &txgbe_pcs_read;
|
||||
mii_bus->write_c45 = &txgbe_pcs_write;
|
||||
mii_bus->parent = &pdev->dev;
|
||||
mii_bus->phy_mask = ~0;
|
||||
mii_bus->priv = wx;
|
||||
snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x",
|
||||
(pdev->bus->number << 8) | pdev->devfn);
|
||||
|
||||
ret = devm_mdiobus_register(&pdev->dev, mii_bus);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xpcs = xpcs_create_mdiodev(mii_bus, 0, PHY_INTERFACE_MODE_10GBASER);
|
||||
if (IS_ERR(xpcs))
|
||||
return PTR_ERR(xpcs);
|
||||
|
||||
txgbe->xpcs = xpcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct wx *wx = gpiochip_get_data(chip);
|
||||
|
@ -432,16 +508,22 @@ int txgbe_init_phy(struct txgbe *txgbe)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = txgbe_mdio_pcs_init(txgbe);
|
||||
if (ret) {
|
||||
wx_err(txgbe->wx, "failed to init mdio pcs: %d\n", ret);
|
||||
goto err_unregister_swnode;
|
||||
}
|
||||
|
||||
ret = txgbe_gpio_init(txgbe);
|
||||
if (ret) {
|
||||
wx_err(txgbe->wx, "failed to init gpio\n");
|
||||
goto err_unregister_swnode;
|
||||
goto err_destroy_xpcs;
|
||||
}
|
||||
|
||||
ret = txgbe_clock_register(txgbe);
|
||||
if (ret) {
|
||||
wx_err(txgbe->wx, "failed to register clock: %d\n", ret);
|
||||
goto err_unregister_swnode;
|
||||
goto err_destroy_xpcs;
|
||||
}
|
||||
|
||||
ret = txgbe_i2c_register(txgbe);
|
||||
|
@ -463,6 +545,8 @@ err_unregister_i2c:
|
|||
err_unregister_clk:
|
||||
clkdev_drop(txgbe->clock);
|
||||
clk_unregister(txgbe->clk);
|
||||
err_destroy_xpcs:
|
||||
xpcs_destroy(txgbe->xpcs);
|
||||
err_unregister_swnode:
|
||||
software_node_unregister_node_group(txgbe->nodes.group);
|
||||
|
||||
|
@ -475,5 +559,6 @@ void txgbe_remove_phy(struct txgbe *txgbe)
|
|||
platform_device_unregister(txgbe->i2c_dev);
|
||||
clkdev_drop(txgbe->clock);
|
||||
clk_unregister(txgbe->clk);
|
||||
xpcs_destroy(txgbe->xpcs);
|
||||
software_node_unregister_node_group(txgbe->nodes.group);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,10 @@
|
|||
/* I2C registers */
|
||||
#define TXGBE_I2C_BASE 0x14900
|
||||
|
||||
/************************************** ETH PHY ******************************/
|
||||
#define TXGBE_XPCS_IDA_ADDR 0x13000
|
||||
#define TXGBE_XPCS_IDA_DATA 0x13004
|
||||
|
||||
/* Part Number String Length */
|
||||
#define TXGBE_PBANUM_LENGTH 32
|
||||
|
||||
|
@ -172,6 +176,7 @@ struct txgbe_nodes {
|
|||
struct txgbe {
|
||||
struct wx *wx;
|
||||
struct txgbe_nodes nodes;
|
||||
struct dw_xpcs *xpcs;
|
||||
struct platform_device *sfp_dev;
|
||||
struct platform_device *i2c_dev;
|
||||
struct clk_lookup *clock;
|
||||
|
|
Loading…
Reference in New Issue