Commit 8e8fc62d authored by David S. Miller's avatar David S. Miller

Merge branch 'txgbe-link-modes'

Jiawen Wu says:

====================
support more link mode for TXGBE

There are three new interface mode support for Wangxun 10Gb NICs:
1000BASE-X, SGMII and XAUI.

Specific configurations are added to XPCS. And external PHY attaching
is added for copper NICs.

v2 -> v3:
- add device identifier read
- restrict pcs soft reset
- add firmware version warning

v1 -> v2:
- use the string "txgbe_pcs_mdio_bus" directly
- use dev_err() instead of pr_err()
- add device quirk flag
- add more macro definitions to explain PMA registers
- move txgbe_enable_sec_tx_path() to mac_finish()
- implement phylink for copper NICs
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1355fe13 ad63f7aa
......@@ -22925,6 +22925,7 @@ S: Maintained
W: https://www.net-swift.com
F: Documentation/networking/device_drivers/ethernet/wangxun/*
F: drivers/net/ethernet/wangxun/
F: drivers/net/pcs/pcs-xpcs-wx.c
WATCHDOG DEVICE DRIVERS
M: Wim Van Sebroeck <wim@linux-watchdog.org>
......
......@@ -41,6 +41,7 @@ config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
depends on COMMON_CLK
select MARVELL_10G_PHY
select REGMAP
select I2C
select I2C_DESIGNWARE_PLATFORM
......
......@@ -205,6 +205,8 @@
#define WX_TSC_CTL 0x1D000
#define WX_TSC_CTL_TX_DIS BIT(1)
#define WX_TSC_CTL_TSEC_DIS BIT(0)
#define WX_TSC_ST 0x1D004
#define WX_TSC_ST_SECTX_RDY BIT(0)
#define WX_TSC_BUF_AE 0x1D00C
#define WX_TSC_BUF_AE_THR GENMASK(9, 0)
......@@ -231,6 +233,24 @@
#define WX_MAC_WDG_TIMEOUT 0x1100C
#define WX_MAC_RX_FLOW_CTRL 0x11090
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
/* MDIO Registers */
#define WX_MSCA 0x11200
#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
#define WX_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
#define WX_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
#define WX_MSCC 0x11204
#define WX_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
enum WX_MSCA_CMD_value {
WX_MSCA_CMD_RSV = 0,
WX_MSCA_CMD_WRITE,
WX_MSCA_CMD_POST_READ,
WX_MSCA_CMD_READ,
};
#define WX_MSCC_SADDR BIT(18)
#define WX_MSCC_BUSY BIT(22)
#define WX_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
#define WX_MMC_CONTROL 0x11800
#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */
......@@ -580,6 +600,13 @@ enum wx_mac_type {
wx_mac_em
};
enum sp_media_type {
sp_media_unknown = 0,
sp_media_fiber,
sp_media_copper,
sp_media_backplane
};
enum em_mac_type {
em_mac_type_unknown = 0,
em_mac_type_mdi,
......@@ -827,6 +854,7 @@ struct wx {
struct wx_bus_info bus;
struct wx_mac_info mac;
enum em_mac_type mac_type;
enum sp_media_type media_type;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl;
struct wx_mac_addr *mac_table;
......
......@@ -37,24 +37,24 @@ static int ngbe_phy_read_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(device_type);
wr32(wx, NGBE_MSCA, command);
command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) |
NGBE_MSCC_BUSY |
NGBE_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command);
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(device_type);
wr32(wx, WX_MSCA, command);
command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
WX_MSCC_BUSY |
WX_MDIO_CLK(6);
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC);
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c22 command did not complete.\n");
return ret;
}
return (u16)rd32(wx, NGBE_MSCC);
return (u16)rd32(wx, WX_MSCC);
}
static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
......@@ -65,19 +65,19 @@ static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int reg
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(device_type);
wr32(wx, NGBE_MSCA, command);
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(device_type);
wr32(wx, WX_MSCA, command);
command = value |
NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) |
NGBE_MSCC_BUSY |
NGBE_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command);
WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
WX_MSCC_BUSY |
WX_MDIO_CLK(6);
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC);
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c22 command did not complete.\n");
......@@ -92,24 +92,24 @@ static int ngbe_phy_read_reg_mdi_c45(struct mii_bus *bus, int phy_addr, int devn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(devnum);
wr32(wx, NGBE_MSCA, command);
command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) |
NGBE_MSCC_BUSY |
NGBE_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command);
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(devnum);
wr32(wx, WX_MSCA, command);
command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
WX_MSCC_BUSY |
WX_MDIO_CLK(6);
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC);
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c45 command did not complete.\n");
return ret;
}
return (u16)rd32(wx, NGBE_MSCC);
return (u16)rd32(wx, WX_MSCC);
}
static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
......@@ -121,19 +121,19 @@ static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */
command = NGBE_MSCA_RA(regnum) |
NGBE_MSCA_PA(phy_addr) |
NGBE_MSCA_DA(devnum);
wr32(wx, NGBE_MSCA, command);
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(devnum);
wr32(wx, WX_MSCA, command);
command = value |
NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) |
NGBE_MSCC_BUSY |
NGBE_MDIO_CLK(6);
wr32(wx, NGBE_MSCC, command);
WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
WX_MSCC_BUSY |
WX_MDIO_CLK(6);
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
100000, false, wx, NGBE_MSCC);
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c45 command did not complete.\n");
......
......@@ -59,25 +59,6 @@
#define NGBE_EEPROM_VERSION_L 0x1D
#define NGBE_EEPROM_VERSION_H 0x1E
/* mdio access */
#define NGBE_MSCA 0x11200
#define NGBE_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
#define NGBE_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
#define NGBE_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
#define NGBE_MSCC 0x11204
#define NGBE_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
enum NGBE_MSCA_CMD_value {
NGBE_MSCA_CMD_RSV = 0,
NGBE_MSCA_CMD_WRITE,
NGBE_MSCA_CMD_POST_READ,
NGBE_MSCA_CMD_READ,
};
#define NGBE_MSCC_SADDR BIT(18)
#define NGBE_MSCC_BUSY BIT(22)
#define NGBE_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
/* Media-dependent registers. */
#define NGBE_MDIO_CLAUSE_SELECT 0x11220
......
......@@ -13,6 +13,34 @@
#include "txgbe_type.h"
#include "txgbe_hw.h"
/**
* txgbe_disable_sec_tx_path - Stops the transmit data path
* @wx: pointer to hardware structure
*
* Stops the transmit data path and waits for the HW to internally empty
* the tx security block
**/
int txgbe_disable_sec_tx_path(struct wx *wx)
{
int val;
wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, WX_TSC_CTL_TX_DIS);
return read_poll_timeout(rd32, val, val & WX_TSC_ST_SECTX_RDY,
1000, 20000, false, wx, WX_TSC_ST);
}
/**
* txgbe_enable_sec_tx_path - Enables the transmit data path
* @wx: pointer to hardware structure
*
* Enables the transmit data path.
**/
void txgbe_enable_sec_tx_path(struct wx *wx)
{
wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, 0);
WX_WRITE_FLUSH(wx);
}
/**
* txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
* @wx: pointer to hardware structure
......@@ -257,17 +285,20 @@ static void txgbe_reset_misc(struct wx *wx)
int txgbe_reset_hw(struct wx *wx)
{
int status;
u32 val;
/* Call adapter stop to disable tx/rx and clear interrupts */
status = wx_stop_adapter(wx);
if (status != 0)
return status;
if (wx->media_type != sp_media_copper) {
u32 val;
val = WX_MIS_RST_LAN_RST(wx->bus.func);
wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
WX_WRITE_FLUSH(wx);
usleep_range(10, 100);
}
status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
if (status != 0)
......
......@@ -4,6 +4,8 @@
#ifndef _TXGBE_HW_H_
#define _TXGBE_HW_H_
int txgbe_disable_sec_tx_path(struct wx *wx);
void txgbe_enable_sec_tx_path(struct wx *wx);
int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size);
int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val);
int txgbe_reset_hw(struct wx *wx);
......
......@@ -300,6 +300,49 @@ static void txgbe_down(struct wx *wx)
wx_clean_all_rx_rings(wx);
}
/**
* txgbe_init_type_code - Initialize the shared code
* @wx: pointer to hardware structure
**/
static void txgbe_init_type_code(struct wx *wx)
{
u8 device_type = wx->subsystem_device_id & 0xF0;
switch (wx->device_id) {
case TXGBE_DEV_ID_SP1000:
case TXGBE_DEV_ID_WX1820:
wx->mac.type = wx_mac_sp;
break;
default:
wx->mac.type = wx_mac_unknown;
break;
}
switch (device_type) {
case TXGBE_ID_SFP:
wx->media_type = sp_media_fiber;
break;
case TXGBE_ID_XAUI:
case TXGBE_ID_SGMII:
wx->media_type = sp_media_copper;
break;
case TXGBE_ID_KR_KX_KX4:
case TXGBE_ID_MAC_XAUI:
case TXGBE_ID_MAC_SGMII:
wx->media_type = sp_media_backplane;
break;
case TXGBE_ID_SFI_XAUI:
if (wx->bus.func == 0)
wx->media_type = sp_media_fiber;
else
wx->media_type = sp_media_copper;
break;
default:
wx->media_type = sp_media_unknown;
break;
}
}
/**
* txgbe_sw_init - Initialize general software structures (struct wx)
* @wx: board private structure to initialize
......@@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx)
return err;
}
switch (wx->device_id) {
case TXGBE_DEV_ID_SP1000:
case TXGBE_DEV_ID_WX1820:
wx->mac.type = wx_mac_sp;
break;
default:
wx->mac.type = wx_mac_unknown;
break;
}
txgbe_init_type_code(wx);
/* Set common capability flags and settings */
wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
......@@ -663,6 +698,9 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
if (etrack_id < 0x20010)
dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
if (!txgbe) {
err = -ENOMEM;
......
......@@ -18,6 +18,7 @@
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
#include "txgbe_hw.h"
static int txgbe_swnodes_register(struct txgbe *txgbe)
{
......@@ -160,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
{
struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
if (interface == PHY_INTERFACE_MODE_10GBASER)
return &txgbe->xpcs->pcs;
return NULL;
}
static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
......@@ -210,8 +214,32 @@ static void txgbe_mac_link_up(struct phylink_config *config,
wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
}
static int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct wx *wx = netdev_priv(to_net_dev(config->dev));
wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
return txgbe_disable_sec_tx_path(wx);
}
static int txgbe_mac_finish(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct wx *wx = netdev_priv(to_net_dev(config->dev));
txgbe_enable_sec_tx_path(wx);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
return 0;
}
static const struct phylink_mac_ops txgbe_mac_ops = {
.mac_select_pcs = txgbe_phylink_mac_select,
.mac_prepare = txgbe_mac_prepare,
.mac_finish = txgbe_mac_finish,
.mac_config = txgbe_mac_config,
.mac_link_down = txgbe_mac_link_down,
.mac_link_up = txgbe_mac_link_up,
......@@ -219,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = {
static int txgbe_phylink_init(struct txgbe *txgbe)
{
struct fwnode_handle *fwnode = NULL;
struct phylink_config *config;
struct fwnode_handle *fwnode;
struct wx *wx = txgbe->wx;
phy_interface_t phy_mode;
struct phylink *phylink;
......@@ -231,14 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
config->dev = &wx->netdev->dev;
config->type = PHYLINK_NETDEV;
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
if (wx->media_type == sp_media_copper) {
phy_mode = PHY_INTERFACE_MODE_XAUI;
__set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
} else {
phy_mode = PHY_INTERFACE_MODE_10GBASER;
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
}
phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);
if (wx->phydev) {
int ret;
ret = phylink_connect_phy(phylink, wx->phydev);
if (ret) {
phylink_destroy(phylink);
return ret;
}
}
txgbe->phylink = phylink;
return 0;
......@@ -431,7 +479,8 @@ static void txgbe_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN)) {
if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
TXGBE_PX_MISC_ETH_AN)) {
u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
......@@ -598,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
return 0;
}
static int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
int devnum, int regnum)
{
struct wx *wx = bus->priv;
u32 val, command;
int ret;
/* setup and write the address cycle command */
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(devnum);
wr32(wx, WX_MSCA, command);
command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c45 command did not complete.\n");
return ret;
}
return (u16)rd32(wx, WX_MSCC);
}
static int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
int devnum, int regnum, u16 value)
{
struct wx *wx = bus->priv;
int ret, command;
u16 val;
/* setup and write the address cycle command */
command = WX_MSCA_RA(regnum) |
WX_MSCA_PA(phy_addr) |
WX_MSCA_DA(devnum);
wr32(wx, WX_MSCA, command);
command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
wr32(wx, WX_MSCC, command);
/* wait to complete */
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c45 command did not complete.\n");
return ret;
}
static int txgbe_ext_phy_init(struct txgbe *txgbe)
{
struct phy_device *phydev;
struct mii_bus *mii_bus;
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_mii_bus";
mii_bus->read_c45 = &txgbe_phy_read;
mii_bus->write_c45 = &txgbe_phy_write;
mii_bus->parent = &pdev->dev;
mii_bus->phy_mask = GENMASK(31, 1);
mii_bus->priv = wx;
snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
(pdev->bus->number << 8) | pdev->devfn);
ret = devm_mdiobus_register(&pdev->dev, mii_bus);
if (ret) {
wx_err(wx, "failed to register MDIO bus: %d\n", ret);
return ret;
}
phydev = phy_find_first(mii_bus);
if (!phydev) {
wx_err(wx, "no PHY found\n");
return -ENODEV;
}
phy_attached_info(phydev);
wx->link = 0;
wx->speed = 0;
wx->duplex = 0;
wx->phydev = phydev;
ret = txgbe_phylink_init(txgbe);
if (ret) {
wx_err(wx, "failed to init phylink: %d\n", ret);
return ret;
}
return 0;
}
int txgbe_init_phy(struct txgbe *txgbe)
{
int ret;
if (txgbe->wx->media_type == sp_media_copper)
return txgbe_ext_phy_init(txgbe);
ret = txgbe_swnodes_register(txgbe);
if (ret) {
wx_err(txgbe->wx, "failed to register software nodes\n");
......@@ -663,6 +819,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe)
{
if (txgbe->wx->media_type == sp_media_copper) {
phylink_disconnect_phy(txgbe->phylink);
phylink_destroy(txgbe->phylink);
return;
}
platform_device_unregister(txgbe->sfp_dev);
platform_device_unregister(txgbe->i2c_dev);
clkdev_drop(txgbe->clock);
......
# SPDX-License-Identifier: GPL-2.0
# Makefile for Linux PCS drivers
pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
#include <linux/pcs/pcs-xpcs.h>
#include <linux/mdio.h>
#include "pcs-xpcs.h"
/* VR_XS_PMA_MMD */
#define TXGBE_PMA_MMD 0x8020
#define TXGBE_TX_GENCTL1 0x11
#define TXGBE_TX_GENCTL1_VBOOST_LVL GENMASK(10, 8)
#define TXGBE_TX_GENCTL1_VBOOST_EN0 BIT(4)
#define TXGBE_TX_GEN_CTL2 0x12
#define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
#define TXGBE_TX_RATE_CTL 0x14
#define TXGBE_TX_RATE_CTL_TX0_RATE(v) FIELD_PREP(GENMASK(2, 0), v)
#define TXGBE_RX_GEN_CTL2 0x32
#define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
#define TXGBE_RX_GEN_CTL3 0x33
#define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0)
#define TXGBE_RX_RATE_CTL 0x34
#define TXGBE_RX_RATE_CTL_RX0_RATE(v) FIELD_PREP(GENMASK(1, 0), v)
#define TXGBE_RX_EQ_ATTN_CTL 0x37
#define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0)
#define TXGBE_RX_EQ_CTL0 0x38
#define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v) FIELD_PREP(GENMASK(15, 12), v)
#define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v) FIELD_PREP(GENMASK(11, 8), v)
#define TXGBE_RX_EQ_CTL0_CTLE_POLE(v) FIELD_PREP(GENMASK(7, 5), v)
#define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v) FIELD_PREP(GENMASK(4, 0), v)
#define TXGBE_RX_EQ_CTL4 0x3C
#define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0 BIT(4)
#define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0)
#define TXGBE_AFE_DFE_ENABLE 0x3D
#define TXGBE_DFE_EN_0 BIT(4)
#define TXGBE_AFE_EN_0 BIT(0)
#define TXGBE_DFE_TAP_CTL0 0x3E
#define TXGBE_MPLLA_CTL0 0x51
#define TXGBE_MPLLA_CTL2 0x53
#define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN BIT(10)
#define TXGBE_MPLLA_CTL2_DIV10_CLK_EN BIT(9)
#define TXGBE_MPLLA_CTL3 0x57
#define TXGBE_MISC_CTL0 0x70
#define TXGBE_MISC_CTL0_PLL BIT(15)
#define TXGBE_MISC_CTL0_CR_PARA_SEL BIT(14)
#define TXGBE_MISC_CTL0_RX_VREF(v) FIELD_PREP(GENMASK(12, 8), v)
#define TXGBE_VCO_CAL_LD0 0x72
#define TXGBE_VCO_CAL_REF0 0x76
static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg)
{
return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg);
}
static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
{
return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);
}
static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)
{
int val;
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);
val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);
txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);
txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);
txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));
txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |
TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |
TXGBE_RX_EQ_CTL0_CTLE_BOOST(5));
val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
val &= ~TXGBE_RX_EQ_ATTN_LVL0;
txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);
val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE);
val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0);
txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val);
val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4);
val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0;
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val);
}
static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)
{
int val;
val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0;
txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |
TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));
val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
val &= ~TXGBE_RX_EQ_ATTN_LVL0;
txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);
val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3);
val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0);
txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);
txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);
txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);
txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);
txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));
txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));
txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));
txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));
txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
}
static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)
{
int val, ret;
/* Wait xpcs power-up good */
ret = read_poll_timeout(xpcs_read_vpcs, val,
(val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD,
10000, 1000000, false,
xpcs, DW_VR_XS_PCS_DIG_STS);
if (ret < 0)
dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n");
return ret;
}
static int txgbe_pma_init_done(struct dw_xpcs *xpcs)
{
int val, ret;
xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);
/* wait pma initialization done */
ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST),
100000, 10000000, false,
xpcs, DW_VR_XS_PCS_DIG_CTRL1);
if (ret < 0)
dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n");
return ret;
}
static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
{
int ret;
/* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
ret &= MDIO_PCS_CTRL2_TYPE;
if ((ret == MDIO_PCS_CTRL2_10GBR &&
xpcs->interface != PHY_INTERFACE_MODE_10GBASER) ||
xpcs->interface == PHY_INTERFACE_MODE_SGMII)
return true;
return false;
}
int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
{
int val, ret;
switch (interface) {
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
break;
default:
return 0;
}
if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs))
return 0;
xpcs->interface = interface;
ret = txgbe_pcs_poll_power_up(xpcs);
if (ret < 0)
return ret;
if (interface == PHY_INTERFACE_MODE_10GBASER) {
xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);
val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1);
val |= MDIO_CTRL1_SPEED10G;
xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val);
txgbe_pma_config_10gbaser(xpcs);
} else {
xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);
xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);
xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);
txgbe_pma_config_1g(xpcs);
}
return txgbe_pma_init_done(xpcs);
}
......@@ -228,16 +228,39 @@ static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
}
static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
{
return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
}
static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
{
return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
}
static int xpcs_dev_flag(struct dw_xpcs *xpcs)
{
int ret, oui;
ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
if (ret < 0)
return ret;
oui = ret;
ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
if (ret < 0)
return ret;
ret = (ret >> 10) & 0x3F;
oui |= ret << 16;
if (oui == DW_OUI_WX)
xpcs->dev_flag = DW_DEV_TXGBE;
return 0;
}
static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
{
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
......@@ -660,7 +683,10 @@ EXPORT_SYMBOL_GPL(xpcs_config_eee);
static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
unsigned int neg_mode)
{
int ret, mdio_ctrl;
int ret, mdio_ctrl, tx_conf;
if (xpcs->dev_flag == DW_DEV_TXGBE)
xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
/* For AN for C37 SGMII mode, the settings are :-
* 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
......@@ -697,9 +723,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
DW_VR_MII_PCS_MODE_MASK);
ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
DW_VR_MII_TX_CONFIG_MASK);
if (xpcs->dev_flag == DW_DEV_TXGBE) {
ret |= DW_VR_MII_AN_CTRL_8BIT;
/* Hardware requires it to be PHY side SGMII */
tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
} else {
tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII;
}
ret |= tx_conf << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
DW_VR_MII_TX_CONFIG_MASK;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0)
return ret;
......@@ -713,6 +745,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
else
ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
if (xpcs->dev_flag == DW_DEV_TXGBE)
ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
if (ret < 0)
return ret;
......@@ -732,6 +767,9 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
int ret, mdio_ctrl, adv;
bool changed = 0;
if (xpcs->dev_flag == DW_DEV_TXGBE)
xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
/* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
* be disabled first:-
* 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
......@@ -753,6 +791,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
return ret;
ret &= ~DW_VR_MII_PCS_MODE_MASK;
if (!xpcs->pcs.poll)
ret |= DW_VR_MII_AN_INTR_EN;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0)
return ret;
......@@ -818,6 +858,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
if (!compat)
return -ENODEV;
if (xpcs->dev_flag == DW_DEV_TXGBE) {
ret = txgbe_xpcs_switch_mode(xpcs, interface);
if (ret)
return ret;
}
switch (compat->an_mode) {
case DW_10GBASER:
break;
......@@ -977,6 +1023,33 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
state->duplex = DUPLEX_FULL;
else
state->duplex = DUPLEX_HALF;
} else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
int speed, duplex;
state->link = true;
speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
if (speed < 0)
return speed;
speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
if (speed == SGMII_SPEED_SS6)
state->speed = SPEED_1000;
else if (speed == SGMII_SPEED_SS13)
state->speed = SPEED_100;
else if (speed == 0)
state->speed = SPEED_10;
duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
if (duplex < 0)
return duplex;
if (duplex & DW_FULL_DUPLEX)
state->duplex = DUPLEX_FULL;
else if (duplex & DW_HALF_DUPLEX)
state->duplex = DUPLEX_HALF;
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
}
return 0;
......@@ -1000,6 +1073,17 @@ static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
if (bmsr < 0)
return bmsr;
/* Clear AN complete interrupt */
if (!xpcs->pcs.poll) {
int an_intr;
an_intr = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
if (an_intr & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
an_intr &= ~DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, an_intr);
}
}
phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
}
......@@ -1284,16 +1368,20 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
goto out;
}
ret = xpcs_dev_flag(xpcs);
if (ret)
goto out;
xpcs->pcs.ops = &xpcs_phylink_ops;
xpcs->pcs.neg_mode = true;
if (compat->an_mode == DW_10GBASER)
return xpcs;
if (xpcs->dev_flag != DW_DEV_TXGBE) {
xpcs->pcs.poll = true;
ret = xpcs_soft_reset(xpcs, compat);
if (ret)
goto out;
}
return xpcs;
}
......
......@@ -15,8 +15,14 @@
/* VR_XS_PCS */
#define DW_USXGMII_RST BIT(10)
#define DW_USXGMII_EN BIT(9)
#define DW_VR_XS_PCS_DIG_CTRL1 0x0000
#define DW_VR_RST BIT(15)
#define DW_EN_VSMMD1 BIT(13)
#define DW_CL37_BP BIT(12)
#define DW_VR_XS_PCS_DIG_STS 0x0010
#define DW_RXFIFO_ERR GENMASK(6, 5)
#define DW_PSEQ_ST GENMASK(4, 2)
#define DW_PSEQ_ST_GOOD FIELD_PREP(GENMASK(4, 2), 0x4)
/* SR_MII */
#define DW_USXGMII_FULL BIT(8)
......@@ -61,12 +67,14 @@
/* VR_MII_DIG_CTRL1 */
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
#define DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL BIT(0)
/* VR_MII_DIG_CTRL2 */
#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
#define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0)
/* VR_MII_AN_CTRL */
#define DW_VR_MII_AN_CTRL_8BIT BIT(8)
#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1
......@@ -75,8 +83,10 @@
#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
#define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0
#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
#define DW_VR_MII_AN_INTR_EN BIT(0)
/* VR_MII_AN_INTR_STS */
#define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR BIT(0)
#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2
#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
......@@ -90,6 +100,10 @@
#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */
#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */
/* SR MII MMD AN Advertisement defines */
#define DW_HALF_DUPLEX BIT(6)
#define DW_FULL_DUPLEX BIT(5)
/* VR MII EEE Control 0 defines */
#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
......@@ -106,6 +120,9 @@
int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg);
int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val);
int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
......@@ -20,12 +20,20 @@
#define DW_AN_C37_1000BASEX 4
#define DW_10GBASER 5
/* device vendor OUI */
#define DW_OUI_WX 0x0018fc80
/* dev_flag */
#define DW_DEV_TXGBE BIT(0)
struct xpcs_id;
struct dw_xpcs {
struct mdio_device *mdiodev;
const struct xpcs_id *id;
struct phylink_pcs pcs;
phy_interface_t interface;
int dev_flag;
};
int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment