net/axgbe: add phy init and related APIs
Added device phy initialization, read/write and other maintenance apis to be used within PMD. Signed-off-by: Ravi Kumar <ravi1.kumar@amd.com>
This commit is contained in:
parent
572890ef66
commit
4ac7516b8b
@ -24,5 +24,8 @@ LDLIBS += -lrte_ethdev
|
||||
#
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_AXGBE_PMD) += axgbe_ethdev.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_AXGBE_PMD) += axgbe_dev.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_AXGBE_PMD) += axgbe_mdio.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_AXGBE_PMD) += axgbe_phy_impl.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_AXGBE_PMD) += axgbe_i2c.c
|
||||
|
||||
include $(RTE_SDK)/mk/rte.lib.mk
|
||||
|
@ -7,6 +7,187 @@
|
||||
#include "axgbe_common.h"
|
||||
#include "axgbe_phy.h"
|
||||
|
||||
/* query busy bit */
|
||||
static int mdio_complete(struct axgbe_port *pdata)
|
||||
{
|
||||
if (!AXGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, BUSY))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axgbe_write_ext_mii_regs(struct axgbe_port *pdata, int addr,
|
||||
int reg, u16 val)
|
||||
{
|
||||
unsigned int mdio_sca, mdio_sccd;
|
||||
uint64_t timeout;
|
||||
|
||||
mdio_sca = 0;
|
||||
AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg);
|
||||
AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr);
|
||||
AXGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
|
||||
|
||||
mdio_sccd = 0;
|
||||
AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, DATA, val);
|
||||
AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 1);
|
||||
AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
|
||||
AXGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
|
||||
|
||||
timeout = rte_get_timer_cycles() + rte_get_timer_hz();
|
||||
while (time_before(rte_get_timer_cycles(), timeout)) {
|
||||
rte_delay_us(100);
|
||||
if (mdio_complete(pdata))
|
||||
return 0;
|
||||
}
|
||||
|
||||
PMD_DRV_LOG(ERR, "Mdio write operation timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int axgbe_read_ext_mii_regs(struct axgbe_port *pdata, int addr,
|
||||
int reg)
|
||||
{
|
||||
unsigned int mdio_sca, mdio_sccd;
|
||||
uint64_t timeout;
|
||||
|
||||
mdio_sca = 0;
|
||||
AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg);
|
||||
AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr);
|
||||
AXGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
|
||||
|
||||
mdio_sccd = 0;
|
||||
AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 3);
|
||||
AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
|
||||
AXGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
|
||||
|
||||
timeout = rte_get_timer_cycles() + rte_get_timer_hz();
|
||||
|
||||
while (time_before(rte_get_timer_cycles(), timeout)) {
|
||||
rte_delay_us(100);
|
||||
if (mdio_complete(pdata))
|
||||
goto success;
|
||||
}
|
||||
|
||||
PMD_DRV_LOG(ERR, "Mdio read operation timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
|
||||
success:
|
||||
return AXGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, DATA);
|
||||
}
|
||||
|
||||
static int axgbe_set_ext_mii_mode(struct axgbe_port *pdata, unsigned int port,
|
||||
enum axgbe_mdio_mode mode)
|
||||
{
|
||||
unsigned int reg_val = 0;
|
||||
|
||||
switch (mode) {
|
||||
case AXGBE_MDIO_MODE_CL22:
|
||||
if (port > AXGMAC_MAX_C22_PORT)
|
||||
return -EINVAL;
|
||||
reg_val |= (1 << port);
|
||||
break;
|
||||
case AXGBE_MDIO_MODE_CL45:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
AXGMAC_IOWRITE(pdata, MAC_MDIOCL22R, reg_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axgbe_read_mmd_regs_v2(struct axgbe_port *pdata,
|
||||
int prtad __rte_unused, int mmd_reg)
|
||||
{
|
||||
unsigned int mmd_address, index, offset;
|
||||
int mmd_data;
|
||||
|
||||
if (mmd_reg & MII_ADDR_C45)
|
||||
mmd_address = mmd_reg & ~MII_ADDR_C45;
|
||||
else
|
||||
mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
|
||||
|
||||
/* The PCS registers are accessed using mmio. The underlying
|
||||
* management interface uses indirect addressing to access the MMD
|
||||
* register sets. This requires accessing of the PCS register in two
|
||||
* phases, an address phase and a data phase.
|
||||
*
|
||||
* The mmio interface is based on 16-bit offsets and values. All
|
||||
* register offsets must therefore be adjusted by left shifting the
|
||||
* offset 1 bit and reading 16 bits of data.
|
||||
*/
|
||||
mmd_address <<= 1;
|
||||
index = mmd_address & ~pdata->xpcs_window_mask;
|
||||
offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
|
||||
|
||||
pthread_mutex_lock(&pdata->xpcs_mutex);
|
||||
|
||||
XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
|
||||
mmd_data = XPCS16_IOREAD(pdata, offset);
|
||||
|
||||
pthread_mutex_unlock(&pdata->xpcs_mutex);
|
||||
|
||||
return mmd_data;
|
||||
}
|
||||
|
||||
static void axgbe_write_mmd_regs_v2(struct axgbe_port *pdata,
|
||||
int prtad __rte_unused,
|
||||
int mmd_reg, int mmd_data)
|
||||
{
|
||||
unsigned int mmd_address, index, offset;
|
||||
|
||||
if (mmd_reg & MII_ADDR_C45)
|
||||
mmd_address = mmd_reg & ~MII_ADDR_C45;
|
||||
else
|
||||
mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
|
||||
|
||||
/* The PCS registers are accessed using mmio. The underlying
|
||||
* management interface uses indirect addressing to access the MMD
|
||||
* register sets. This requires accessing of the PCS register in two
|
||||
* phases, an address phase and a data phase.
|
||||
*
|
||||
* The mmio interface is based on 16-bit offsets and values. All
|
||||
* register offsets must therefore be adjusted by left shifting the
|
||||
* offset 1 bit and writing 16 bits of data.
|
||||
*/
|
||||
mmd_address <<= 1;
|
||||
index = mmd_address & ~pdata->xpcs_window_mask;
|
||||
offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
|
||||
|
||||
pthread_mutex_lock(&pdata->xpcs_mutex);
|
||||
|
||||
XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
|
||||
XPCS16_IOWRITE(pdata, offset, mmd_data);
|
||||
|
||||
pthread_mutex_unlock(&pdata->xpcs_mutex);
|
||||
}
|
||||
|
||||
static int axgbe_read_mmd_regs(struct axgbe_port *pdata, int prtad,
|
||||
int mmd_reg)
|
||||
{
|
||||
switch (pdata->vdata->xpcs_access) {
|
||||
case AXGBE_XPCS_ACCESS_V1:
|
||||
PMD_DRV_LOG(ERR, "PHY_Version 1 is not supported\n");
|
||||
return -1;
|
||||
case AXGBE_XPCS_ACCESS_V2:
|
||||
default:
|
||||
return axgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void axgbe_write_mmd_regs(struct axgbe_port *pdata, int prtad,
|
||||
int mmd_reg, int mmd_data)
|
||||
{
|
||||
switch (pdata->vdata->xpcs_access) {
|
||||
case AXGBE_XPCS_ACCESS_V1:
|
||||
PMD_DRV_LOG(ERR, "PHY_Version 1 is not supported\n");
|
||||
return;
|
||||
case AXGBE_XPCS_ACCESS_V2:
|
||||
default:
|
||||
return axgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data);
|
||||
}
|
||||
}
|
||||
|
||||
static int __axgbe_exit(struct axgbe_port *pdata)
|
||||
{
|
||||
unsigned int count = 2000;
|
||||
@ -42,4 +223,11 @@ static int axgbe_exit(struct axgbe_port *pdata)
|
||||
void axgbe_init_function_ptrs_dev(struct axgbe_hw_if *hw_if)
|
||||
{
|
||||
hw_if->exit = axgbe_exit;
|
||||
|
||||
hw_if->read_mmd_regs = axgbe_read_mmd_regs;
|
||||
hw_if->write_mmd_regs = axgbe_write_mmd_regs;
|
||||
|
||||
hw_if->set_ext_mii_mode = axgbe_set_ext_mii_mode;
|
||||
hw_if->read_ext_mii_regs = axgbe_read_ext_mii_regs;
|
||||
hw_if->write_ext_mii_regs = axgbe_write_ext_mii_regs;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ static const struct rte_pci_id pci_id_axgbe_map[] = {
|
||||
};
|
||||
|
||||
static struct axgbe_version_data axgbe_v2a = {
|
||||
.init_function_ptrs_phy_impl = axgbe_init_function_ptrs_phy_v2,
|
||||
.xpcs_access = AXGBE_XPCS_ACCESS_V2,
|
||||
.mmc_64bit = 1,
|
||||
.tx_max_fifo_size = 229376,
|
||||
@ -35,6 +36,7 @@ static struct axgbe_version_data axgbe_v2a = {
|
||||
};
|
||||
|
||||
static struct axgbe_version_data axgbe_v2b = {
|
||||
.init_function_ptrs_phy_impl = axgbe_init_function_ptrs_phy_v2,
|
||||
.xpcs_access = AXGBE_XPCS_ACCESS_V2,
|
||||
.mmc_64bit = 1,
|
||||
.tx_max_fifo_size = 65536,
|
||||
@ -149,6 +151,9 @@ static void axgbe_get_all_hw_features(struct axgbe_port *pdata)
|
||||
static void axgbe_init_all_fptrs(struct axgbe_port *pdata)
|
||||
{
|
||||
axgbe_init_function_ptrs_dev(&pdata->hw_if);
|
||||
axgbe_init_function_ptrs_phy(&pdata->phy_if);
|
||||
axgbe_init_function_ptrs_i2c(&pdata->i2c_if);
|
||||
pdata->vdata->init_function_ptrs_phy_impl(&pdata->phy_if);
|
||||
}
|
||||
|
||||
static void axgbe_set_counts(struct axgbe_port *pdata)
|
||||
@ -336,6 +341,12 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
|
||||
pthread_mutex_init(&pdata->an_mutex, NULL);
|
||||
pthread_mutex_init(&pdata->phy_mutex, NULL);
|
||||
|
||||
ret = pdata->phy_if.phy_init(pdata);
|
||||
if (ret) {
|
||||
rte_free(eth_dev->data->mac_addrs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
|
||||
eth_dev->data->port_id, pci_dev->id.vendor_id,
|
||||
pci_dev->id.device_id);
|
||||
|
@ -189,6 +189,61 @@ enum axgbe_mdio_mode {
|
||||
AXGBE_MDIO_MODE_CL45,
|
||||
};
|
||||
|
||||
struct axgbe_phy {
|
||||
uint32_t supported;
|
||||
uint32_t advertising;
|
||||
uint32_t lp_advertising;
|
||||
|
||||
int address;
|
||||
|
||||
int autoneg;
|
||||
int speed;
|
||||
int duplex;
|
||||
|
||||
int link;
|
||||
|
||||
int pause_autoneg;
|
||||
int tx_pause;
|
||||
int rx_pause;
|
||||
};
|
||||
|
||||
enum axgbe_i2c_cmd {
|
||||
AXGBE_I2C_CMD_READ = 0,
|
||||
AXGBE_I2C_CMD_WRITE,
|
||||
};
|
||||
|
||||
struct axgbe_i2c_op {
|
||||
enum axgbe_i2c_cmd cmd;
|
||||
|
||||
unsigned int target;
|
||||
|
||||
uint8_t *buf;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct axgbe_i2c_op_state {
|
||||
struct axgbe_i2c_op *op;
|
||||
|
||||
unsigned int tx_len;
|
||||
unsigned char *tx_buf;
|
||||
|
||||
unsigned int rx_len;
|
||||
unsigned char *rx_buf;
|
||||
|
||||
unsigned int tx_abort_source;
|
||||
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct axgbe_i2c {
|
||||
unsigned int started;
|
||||
unsigned int max_speed_mode;
|
||||
unsigned int rx_fifo_size;
|
||||
unsigned int tx_fifo_size;
|
||||
|
||||
struct axgbe_i2c_op_state op_state;
|
||||
};
|
||||
|
||||
struct axgbe_hw_if {
|
||||
void (*config_flow_control)(struct axgbe_port *);
|
||||
int (*config_rx_mode)(struct axgbe_port *);
|
||||
@ -211,6 +266,89 @@ struct axgbe_hw_if {
|
||||
int (*exit)(struct axgbe_port *);
|
||||
};
|
||||
|
||||
/* This structure represents implementation specific routines for an
|
||||
* implementation of a PHY. All routines are required unless noted below.
|
||||
* Optional routines:
|
||||
* kr_training_pre, kr_training_post
|
||||
*/
|
||||
struct axgbe_phy_impl_if {
|
||||
/* Perform Setup/teardown actions */
|
||||
int (*init)(struct axgbe_port *);
|
||||
void (*exit)(struct axgbe_port *);
|
||||
|
||||
/* Perform start/stop specific actions */
|
||||
int (*reset)(struct axgbe_port *);
|
||||
int (*start)(struct axgbe_port *);
|
||||
void (*stop)(struct axgbe_port *);
|
||||
|
||||
/* Return the link status */
|
||||
int (*link_status)(struct axgbe_port *, int *);
|
||||
|
||||
/* Indicate if a particular speed is valid */
|
||||
int (*valid_speed)(struct axgbe_port *, int);
|
||||
|
||||
/* Check if the specified mode can/should be used */
|
||||
bool (*use_mode)(struct axgbe_port *, enum axgbe_mode);
|
||||
/* Switch the PHY into various modes */
|
||||
void (*set_mode)(struct axgbe_port *, enum axgbe_mode);
|
||||
/* Retrieve mode needed for a specific speed */
|
||||
enum axgbe_mode (*get_mode)(struct axgbe_port *, int);
|
||||
/* Retrieve new/next mode when trying to auto-negotiate */
|
||||
enum axgbe_mode (*switch_mode)(struct axgbe_port *);
|
||||
/* Retrieve current mode */
|
||||
enum axgbe_mode (*cur_mode)(struct axgbe_port *);
|
||||
|
||||
/* Retrieve current auto-negotiation mode */
|
||||
enum axgbe_an_mode (*an_mode)(struct axgbe_port *);
|
||||
|
||||
/* Configure auto-negotiation settings */
|
||||
int (*an_config)(struct axgbe_port *);
|
||||
|
||||
/* Set/override auto-negotiation advertisement settings */
|
||||
unsigned int (*an_advertising)(struct axgbe_port *port);
|
||||
|
||||
/* Process results of auto-negotiation */
|
||||
enum axgbe_mode (*an_outcome)(struct axgbe_port *);
|
||||
|
||||
/* Pre/Post KR training enablement support */
|
||||
void (*kr_training_pre)(struct axgbe_port *);
|
||||
void (*kr_training_post)(struct axgbe_port *);
|
||||
};
|
||||
|
||||
struct axgbe_phy_if {
|
||||
/* For PHY setup/teardown */
|
||||
int (*phy_init)(struct axgbe_port *);
|
||||
void (*phy_exit)(struct axgbe_port *);
|
||||
|
||||
/* For PHY support when setting device up/down */
|
||||
int (*phy_reset)(struct axgbe_port *);
|
||||
int (*phy_start)(struct axgbe_port *);
|
||||
void (*phy_stop)(struct axgbe_port *);
|
||||
|
||||
/* For PHY support while device is up */
|
||||
void (*phy_status)(struct axgbe_port *);
|
||||
int (*phy_config_aneg)(struct axgbe_port *);
|
||||
|
||||
/* For PHY settings validation */
|
||||
int (*phy_valid_speed)(struct axgbe_port *, int);
|
||||
/* For single interrupt support */
|
||||
void (*an_isr)(struct axgbe_port *);
|
||||
/* PHY implementation specific services */
|
||||
struct axgbe_phy_impl_if phy_impl;
|
||||
};
|
||||
|
||||
struct axgbe_i2c_if {
|
||||
/* For initial I2C setup */
|
||||
int (*i2c_init)(struct axgbe_port *);
|
||||
|
||||
/* For I2C support when setting device up/down */
|
||||
int (*i2c_start)(struct axgbe_port *);
|
||||
void (*i2c_stop)(struct axgbe_port *);
|
||||
|
||||
/* For performing I2C operations */
|
||||
int (*i2c_xfer)(struct axgbe_port *, struct axgbe_i2c_op *);
|
||||
};
|
||||
|
||||
/* This structure contains flags that indicate what hardware features
|
||||
* or configurations are present in the device.
|
||||
*/
|
||||
@ -258,6 +396,7 @@ struct axgbe_hw_features {
|
||||
};
|
||||
|
||||
struct axgbe_version_data {
|
||||
void (*init_function_ptrs_phy_impl)(struct axgbe_phy_if *);
|
||||
enum axgbe_xpcs_access xpcs_access;
|
||||
unsigned int mmc_64bit;
|
||||
unsigned int tx_max_fifo_size;
|
||||
@ -295,6 +434,8 @@ struct axgbe_port {
|
||||
unsigned long dev_state;
|
||||
|
||||
struct axgbe_hw_if hw_if;
|
||||
struct axgbe_phy_if phy_if;
|
||||
struct axgbe_i2c_if i2c_if;
|
||||
|
||||
/* AXI DMA settings */
|
||||
unsigned int coherent;
|
||||
@ -366,7 +507,38 @@ struct axgbe_port {
|
||||
struct axgbe_hw_features hw_feat;
|
||||
|
||||
struct ether_addr mac_addr;
|
||||
|
||||
/* MDIO/PHY related settings */
|
||||
unsigned int phy_started;
|
||||
void *phy_data;
|
||||
struct axgbe_phy phy;
|
||||
int mdio_mmd;
|
||||
unsigned long link_check;
|
||||
volatile int mdio_completion;
|
||||
|
||||
unsigned int kr_redrv;
|
||||
|
||||
/* Auto-negotiation atate machine support */
|
||||
unsigned int an_int;
|
||||
unsigned int an_status;
|
||||
enum axgbe_an an_result;
|
||||
enum axgbe_an an_state;
|
||||
enum axgbe_rx kr_state;
|
||||
enum axgbe_rx kx_state;
|
||||
unsigned int an_supported;
|
||||
unsigned int parallel_detect;
|
||||
unsigned int fec_ability;
|
||||
unsigned long an_start;
|
||||
enum axgbe_an_mode an_mode;
|
||||
|
||||
/* I2C support */
|
||||
struct axgbe_i2c i2c;
|
||||
volatile int i2c_complete;
|
||||
};
|
||||
|
||||
void axgbe_init_function_ptrs_dev(struct axgbe_hw_if *hw_if);
|
||||
void axgbe_init_function_ptrs_phy(struct axgbe_phy_if *phy_if);
|
||||
void axgbe_init_function_ptrs_phy_v2(struct axgbe_phy_if *phy_if);
|
||||
void axgbe_init_function_ptrs_i2c(struct axgbe_i2c_if *i2c_if);
|
||||
|
||||
#endif /* RTE_ETH_AXGBE_H_ */
|
||||
|
331
drivers/net/axgbe/axgbe_i2c.c
Normal file
331
drivers/net/axgbe/axgbe_i2c.c
Normal file
@ -0,0 +1,331 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
|
||||
* Copyright(c) 2018 Synopsys, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "axgbe_ethdev.h"
|
||||
#include "axgbe_common.h"
|
||||
|
||||
#define AXGBE_ABORT_COUNT 500
|
||||
#define AXGBE_DISABLE_COUNT 1000
|
||||
|
||||
#define AXGBE_STD_SPEED 1
|
||||
|
||||
#define AXGBE_INTR_RX_FULL BIT(IC_RAW_INTR_STAT_RX_FULL_INDEX)
|
||||
#define AXGBE_INTR_TX_EMPTY BIT(IC_RAW_INTR_STAT_TX_EMPTY_INDEX)
|
||||
#define AXGBE_INTR_TX_ABRT BIT(IC_RAW_INTR_STAT_TX_ABRT_INDEX)
|
||||
#define AXGBE_INTR_STOP_DET BIT(IC_RAW_INTR_STAT_STOP_DET_INDEX)
|
||||
#define AXGBE_DEFAULT_INT_MASK (AXGBE_INTR_RX_FULL | \
|
||||
AXGBE_INTR_TX_EMPTY | \
|
||||
AXGBE_INTR_TX_ABRT | \
|
||||
AXGBE_INTR_STOP_DET)
|
||||
|
||||
#define AXGBE_I2C_READ BIT(8)
|
||||
#define AXGBE_I2C_STOP BIT(9)
|
||||
|
||||
static int axgbe_i2c_abort(struct axgbe_port *pdata)
|
||||
{
|
||||
unsigned int wait = AXGBE_ABORT_COUNT;
|
||||
|
||||
/* Must be enabled to recognize the abort request */
|
||||
XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, 1);
|
||||
|
||||
/* Issue the abort */
|
||||
XI2C_IOWRITE_BITS(pdata, IC_ENABLE, ABORT, 1);
|
||||
|
||||
while (wait--) {
|
||||
if (!XI2C_IOREAD_BITS(pdata, IC_ENABLE, ABORT))
|
||||
return 0;
|
||||
rte_delay_us(500);
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int axgbe_i2c_set_enable(struct axgbe_port *pdata, bool enable)
|
||||
{
|
||||
unsigned int wait = AXGBE_DISABLE_COUNT;
|
||||
unsigned int mode = enable ? 1 : 0;
|
||||
|
||||
while (wait--) {
|
||||
XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, mode);
|
||||
if (XI2C_IOREAD_BITS(pdata, IC_ENABLE_STATUS, EN) == mode)
|
||||
return 0;
|
||||
|
||||
rte_delay_us(100);
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int axgbe_i2c_disable(struct axgbe_port *pdata)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
ret = axgbe_i2c_set_enable(pdata, false);
|
||||
if (ret) {
|
||||
/* Disable failed, try an abort */
|
||||
ret = axgbe_i2c_abort(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Abort succeeded, try to disable again */
|
||||
ret = axgbe_i2c_set_enable(pdata, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int axgbe_i2c_enable(struct axgbe_port *pdata)
|
||||
{
|
||||
return axgbe_i2c_set_enable(pdata, true);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_clear_all_interrupts(struct axgbe_port *pdata)
|
||||
{
|
||||
XI2C_IOREAD(pdata, IC_CLR_INTR);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_disable_interrupts(struct axgbe_port *pdata)
|
||||
{
|
||||
XI2C_IOWRITE(pdata, IC_INTR_MASK, 0);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_enable_interrupts(struct axgbe_port *pdata)
|
||||
{
|
||||
XI2C_IOWRITE(pdata, IC_INTR_MASK, AXGBE_DEFAULT_INT_MASK);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_write(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
|
||||
unsigned int tx_slots;
|
||||
unsigned int cmd;
|
||||
|
||||
/* Configured to never receive Rx overflows, so fill up Tx fifo */
|
||||
tx_slots = pdata->i2c.tx_fifo_size - XI2C_IOREAD(pdata, IC_TXFLR);
|
||||
while (tx_slots && state->tx_len) {
|
||||
if (state->op->cmd == AXGBE_I2C_CMD_READ)
|
||||
cmd = AXGBE_I2C_READ;
|
||||
else
|
||||
cmd = *state->tx_buf++;
|
||||
|
||||
if (state->tx_len == 1)
|
||||
XI2C_SET_BITS(cmd, IC_DATA_CMD, STOP, 1);
|
||||
|
||||
XI2C_IOWRITE(pdata, IC_DATA_CMD, cmd);
|
||||
|
||||
tx_slots--;
|
||||
state->tx_len--;
|
||||
}
|
||||
|
||||
/* No more Tx operations, so ignore TX_EMPTY and return */
|
||||
if (!state->tx_len)
|
||||
XI2C_IOWRITE_BITS(pdata, IC_INTR_MASK, TX_EMPTY, 0);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_read(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
|
||||
unsigned int rx_slots;
|
||||
|
||||
/* Anything to be read? */
|
||||
if (state->op->cmd != AXGBE_I2C_CMD_READ)
|
||||
return;
|
||||
|
||||
rx_slots = XI2C_IOREAD(pdata, IC_RXFLR);
|
||||
while (rx_slots && state->rx_len) {
|
||||
*state->rx_buf++ = XI2C_IOREAD(pdata, IC_DATA_CMD);
|
||||
state->rx_len--;
|
||||
rx_slots--;
|
||||
}
|
||||
}
|
||||
|
||||
static void axgbe_i2c_clear_isr_interrupts(struct axgbe_port *pdata,
|
||||
unsigned int isr)
|
||||
{
|
||||
struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
|
||||
|
||||
if (isr & AXGBE_INTR_TX_ABRT) {
|
||||
state->tx_abort_source = XI2C_IOREAD(pdata, IC_TX_ABRT_SOURCE);
|
||||
XI2C_IOREAD(pdata, IC_CLR_TX_ABRT);
|
||||
}
|
||||
|
||||
if (isr & AXGBE_INTR_STOP_DET)
|
||||
XI2C_IOREAD(pdata, IC_CLR_STOP_DET);
|
||||
}
|
||||
|
||||
static int axgbe_i2c_isr(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
|
||||
unsigned int isr;
|
||||
|
||||
isr = XI2C_IOREAD(pdata, IC_RAW_INTR_STAT);
|
||||
|
||||
axgbe_i2c_clear_isr_interrupts(pdata, isr);
|
||||
|
||||
if (isr & AXGBE_INTR_TX_ABRT) {
|
||||
axgbe_i2c_disable_interrupts(pdata);
|
||||
|
||||
state->ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for data in the Rx fifo */
|
||||
axgbe_i2c_read(pdata);
|
||||
|
||||
/* Fill up the Tx fifo next */
|
||||
axgbe_i2c_write(pdata);
|
||||
|
||||
out:
|
||||
/* Complete on an error or STOP condition */
|
||||
if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void axgbe_i2c_set_mode(struct axgbe_port *pdata)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = XI2C_IOREAD(pdata, IC_CON);
|
||||
XI2C_SET_BITS(reg, IC_CON, MASTER_MODE, 1);
|
||||
XI2C_SET_BITS(reg, IC_CON, SLAVE_DISABLE, 1);
|
||||
XI2C_SET_BITS(reg, IC_CON, RESTART_EN, 1);
|
||||
XI2C_SET_BITS(reg, IC_CON, SPEED, AXGBE_STD_SPEED);
|
||||
XI2C_SET_BITS(reg, IC_CON, RX_FIFO_FULL_HOLD, 1);
|
||||
XI2C_IOWRITE(pdata, IC_CON, reg);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_get_features(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_i2c *i2c = &pdata->i2c;
|
||||
unsigned int reg;
|
||||
|
||||
reg = XI2C_IOREAD(pdata, IC_COMP_PARAM_1);
|
||||
i2c->max_speed_mode = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
|
||||
MAX_SPEED_MODE);
|
||||
i2c->rx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
|
||||
RX_BUFFER_DEPTH);
|
||||
i2c->tx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
|
||||
TX_BUFFER_DEPTH);
|
||||
}
|
||||
|
||||
static void axgbe_i2c_set_target(struct axgbe_port *pdata, unsigned int addr)
|
||||
{
|
||||
XI2C_IOWRITE(pdata, IC_TAR, addr);
|
||||
}
|
||||
|
||||
static int axgbe_i2c_xfer(struct axgbe_port *pdata, struct axgbe_i2c_op *op)
|
||||
{
|
||||
struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
|
||||
int ret;
|
||||
uint64_t timeout;
|
||||
|
||||
pthread_mutex_lock(&pdata->i2c_mutex);
|
||||
ret = axgbe_i2c_disable(pdata);
|
||||
if (ret) {
|
||||
PMD_DRV_LOG(ERR, "failed to disable i2c master\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
axgbe_i2c_set_target(pdata, op->target);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->op = op;
|
||||
state->tx_len = op->len;
|
||||
state->tx_buf = (unsigned char *)op->buf;
|
||||
state->rx_len = op->len;
|
||||
state->rx_buf = (unsigned char *)op->buf;
|
||||
|
||||
axgbe_i2c_clear_all_interrupts(pdata);
|
||||
ret = axgbe_i2c_enable(pdata);
|
||||
if (ret) {
|
||||
PMD_DRV_LOG(ERR, "failed to enable i2c master\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enabling the interrupts will cause the TX FIFO empty interrupt to
|
||||
* fire and begin to process the command via the ISR.
|
||||
*/
|
||||
axgbe_i2c_enable_interrupts(pdata);
|
||||
timeout = rte_get_timer_cycles() + rte_get_timer_hz();
|
||||
|
||||
while (time_before(rte_get_timer_cycles(), timeout)) {
|
||||
rte_delay_us(100);
|
||||
if (XI2C_IOREAD(pdata, IC_RAW_INTR_STAT)) {
|
||||
if (axgbe_i2c_isr(pdata))
|
||||
goto success;
|
||||
}
|
||||
}
|
||||
|
||||
PMD_DRV_LOG(ERR, "i2c operation timed out\n");
|
||||
axgbe_i2c_disable_interrupts(pdata);
|
||||
axgbe_i2c_disable(pdata);
|
||||
ret = -ETIMEDOUT;
|
||||
goto unlock;
|
||||
|
||||
success:
|
||||
ret = state->ret;
|
||||
if (ret) {
|
||||
if (state->tx_abort_source & IC_TX_ABRT_7B_ADDR_NOACK)
|
||||
ret = -ENOTCONN;
|
||||
else if (state->tx_abort_source & IC_TX_ABRT_ARB_LOST)
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
unlock:
|
||||
pthread_mutex_unlock(&pdata->i2c_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void axgbe_i2c_stop(struct axgbe_port *pdata)
|
||||
{
|
||||
if (!pdata->i2c.started)
|
||||
return;
|
||||
|
||||
pdata->i2c.started = 0;
|
||||
axgbe_i2c_disable_interrupts(pdata);
|
||||
axgbe_i2c_disable(pdata);
|
||||
axgbe_i2c_clear_all_interrupts(pdata);
|
||||
}
|
||||
|
||||
static int axgbe_i2c_start(struct axgbe_port *pdata)
|
||||
{
|
||||
if (pdata->i2c.started)
|
||||
return 0;
|
||||
|
||||
pdata->i2c.started = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axgbe_i2c_init(struct axgbe_port *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
axgbe_i2c_disable_interrupts(pdata);
|
||||
|
||||
ret = axgbe_i2c_disable(pdata);
|
||||
if (ret) {
|
||||
PMD_DRV_LOG(ERR, "failed to disable i2c master\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
axgbe_i2c_get_features(pdata);
|
||||
|
||||
axgbe_i2c_set_mode(pdata);
|
||||
|
||||
axgbe_i2c_clear_all_interrupts(pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void axgbe_init_function_ptrs_i2c(struct axgbe_i2c_if *i2c_if)
|
||||
{
|
||||
i2c_if->i2c_init = axgbe_i2c_init;
|
||||
i2c_if->i2c_start = axgbe_i2c_start;
|
||||
i2c_if->i2c_stop = axgbe_i2c_stop;
|
||||
i2c_if->i2c_xfer = axgbe_i2c_xfer;
|
||||
}
|
81
drivers/net/axgbe/axgbe_mdio.c
Normal file
81
drivers/net/axgbe/axgbe_mdio.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
|
||||
* Copyright(c) 2018 Synopsys, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "axgbe_ethdev.h"
|
||||
#include "axgbe_common.h"
|
||||
#include "axgbe_phy.h"
|
||||
|
||||
static int axgbe_phy_best_advertised_speed(struct axgbe_port *pdata)
|
||||
{
|
||||
if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
|
||||
return SPEED_10000;
|
||||
else if (pdata->phy.advertising & ADVERTISED_10000baseT_Full)
|
||||
return SPEED_10000;
|
||||
else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
|
||||
return SPEED_2500;
|
||||
else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
|
||||
return SPEED_1000;
|
||||
else if (pdata->phy.advertising & ADVERTISED_1000baseT_Full)
|
||||
return SPEED_1000;
|
||||
else if (pdata->phy.advertising & ADVERTISED_100baseT_Full)
|
||||
return SPEED_100;
|
||||
|
||||
return SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
static int axgbe_phy_init(struct axgbe_port *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pdata->mdio_mmd = MDIO_MMD_PCS;
|
||||
|
||||
/* Check for FEC support */
|
||||
pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
|
||||
MDIO_PMA_10GBR_FECABLE);
|
||||
pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
|
||||
MDIO_PMA_10GBR_FECABLE_ERRABLE);
|
||||
|
||||
/* Setup the phy (including supported features) */
|
||||
ret = pdata->phy_if.phy_impl.init(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
pdata->phy.advertising = pdata->phy.supported;
|
||||
|
||||
pdata->phy.address = 0;
|
||||
|
||||
if (pdata->phy.advertising & ADVERTISED_Autoneg) {
|
||||
pdata->phy.autoneg = AUTONEG_ENABLE;
|
||||
pdata->phy.speed = SPEED_UNKNOWN;
|
||||
pdata->phy.duplex = DUPLEX_UNKNOWN;
|
||||
} else {
|
||||
pdata->phy.autoneg = AUTONEG_DISABLE;
|
||||
pdata->phy.speed = axgbe_phy_best_advertised_speed(pdata);
|
||||
pdata->phy.duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
pdata->phy.link = 0;
|
||||
|
||||
pdata->phy.pause_autoneg = pdata->pause_autoneg;
|
||||
pdata->phy.tx_pause = pdata->tx_pause;
|
||||
pdata->phy.rx_pause = pdata->rx_pause;
|
||||
|
||||
/* Fix up Flow Control advertising */
|
||||
pdata->phy.advertising &= ~ADVERTISED_Pause;
|
||||
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
|
||||
|
||||
if (pdata->rx_pause) {
|
||||
pdata->phy.advertising |= ADVERTISED_Pause;
|
||||
pdata->phy.advertising |= ADVERTISED_Asym_Pause;
|
||||
}
|
||||
|
||||
if (pdata->tx_pause)
|
||||
pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void axgbe_init_function_ptrs_phy(struct axgbe_phy_if *phy_if)
|
||||
{
|
||||
phy_if->phy_init = axgbe_phy_init;
|
||||
}
|
677
drivers/net/axgbe/axgbe_phy_impl.c
Normal file
677
drivers/net/axgbe/axgbe_phy_impl.c
Normal file
@ -0,0 +1,677 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
|
||||
* Copyright(c) 2018 Synopsys, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "axgbe_ethdev.h"
|
||||
#include "axgbe_common.h"
|
||||
#include "axgbe_phy.h"
|
||||
|
||||
#define AXGBE_PHY_PORT_SPEED_100 BIT(0)
|
||||
#define AXGBE_PHY_PORT_SPEED_1000 BIT(1)
|
||||
#define AXGBE_PHY_PORT_SPEED_2500 BIT(2)
|
||||
#define AXGBE_PHY_PORT_SPEED_10000 BIT(3)
|
||||
|
||||
#define AXGBE_MUTEX_RELEASE 0x80000000
|
||||
|
||||
#define AXGBE_SFP_DIRECT 7
|
||||
|
||||
/* I2C target addresses */
|
||||
#define AXGBE_SFP_SERIAL_ID_ADDRESS 0x50
|
||||
#define AXGBE_SFP_DIAG_INFO_ADDRESS 0x51
|
||||
#define AXGBE_SFP_PHY_ADDRESS 0x56
|
||||
#define AXGBE_GPIO_ADDRESS_PCA9555 0x20
|
||||
|
||||
/* SFP sideband signal indicators */
|
||||
#define AXGBE_GPIO_NO_TX_FAULT BIT(0)
|
||||
#define AXGBE_GPIO_NO_RATE_SELECT BIT(1)
|
||||
#define AXGBE_GPIO_NO_MOD_ABSENT BIT(2)
|
||||
#define AXGBE_GPIO_NO_RX_LOS BIT(3)
|
||||
|
||||
/* Rate-change complete wait/retry count */
|
||||
#define AXGBE_RATECHANGE_COUNT 500
|
||||
|
||||
enum axgbe_port_mode {
|
||||
AXGBE_PORT_MODE_RSVD = 0,
|
||||
AXGBE_PORT_MODE_BACKPLANE,
|
||||
AXGBE_PORT_MODE_BACKPLANE_2500,
|
||||
AXGBE_PORT_MODE_1000BASE_T,
|
||||
AXGBE_PORT_MODE_1000BASE_X,
|
||||
AXGBE_PORT_MODE_NBASE_T,
|
||||
AXGBE_PORT_MODE_10GBASE_T,
|
||||
AXGBE_PORT_MODE_10GBASE_R,
|
||||
AXGBE_PORT_MODE_SFP,
|
||||
AXGBE_PORT_MODE_MAX,
|
||||
};
|
||||
|
||||
enum axgbe_conn_type {
|
||||
AXGBE_CONN_TYPE_NONE = 0,
|
||||
AXGBE_CONN_TYPE_SFP,
|
||||
AXGBE_CONN_TYPE_MDIO,
|
||||
AXGBE_CONN_TYPE_RSVD1,
|
||||
AXGBE_CONN_TYPE_BACKPLANE,
|
||||
AXGBE_CONN_TYPE_MAX,
|
||||
};
|
||||
|
||||
/* SFP/SFP+ related definitions */
|
||||
enum axgbe_sfp_comm {
|
||||
AXGBE_SFP_COMM_DIRECT = 0,
|
||||
AXGBE_SFP_COMM_PCA9545,
|
||||
};
|
||||
|
||||
enum axgbe_sfp_cable {
|
||||
AXGBE_SFP_CABLE_UNKNOWN = 0,
|
||||
AXGBE_SFP_CABLE_ACTIVE,
|
||||
AXGBE_SFP_CABLE_PASSIVE,
|
||||
};
|
||||
|
||||
enum axgbe_sfp_base {
|
||||
AXGBE_SFP_BASE_UNKNOWN = 0,
|
||||
AXGBE_SFP_BASE_1000_T,
|
||||
AXGBE_SFP_BASE_1000_SX,
|
||||
AXGBE_SFP_BASE_1000_LX,
|
||||
AXGBE_SFP_BASE_1000_CX,
|
||||
AXGBE_SFP_BASE_10000_SR,
|
||||
AXGBE_SFP_BASE_10000_LR,
|
||||
AXGBE_SFP_BASE_10000_LRM,
|
||||
AXGBE_SFP_BASE_10000_ER,
|
||||
AXGBE_SFP_BASE_10000_CR,
|
||||
};
|
||||
|
||||
enum axgbe_sfp_speed {
|
||||
AXGBE_SFP_SPEED_UNKNOWN = 0,
|
||||
AXGBE_SFP_SPEED_100_1000,
|
||||
AXGBE_SFP_SPEED_1000,
|
||||
AXGBE_SFP_SPEED_10000,
|
||||
};
|
||||
|
||||
/* SFP Serial ID Base ID values relative to an offset of 0 */
|
||||
#define AXGBE_SFP_BASE_ID 0
|
||||
#define AXGBE_SFP_ID_SFP 0x03
|
||||
|
||||
#define AXGBE_SFP_BASE_EXT_ID 1
|
||||
#define AXGBE_SFP_EXT_ID_SFP 0x04
|
||||
|
||||
#define AXGBE_SFP_BASE_10GBE_CC 3
|
||||
#define AXGBE_SFP_BASE_10GBE_CC_SR BIT(4)
|
||||
#define AXGBE_SFP_BASE_10GBE_CC_LR BIT(5)
|
||||
#define AXGBE_SFP_BASE_10GBE_CC_LRM BIT(6)
|
||||
#define AXGBE_SFP_BASE_10GBE_CC_ER BIT(7)
|
||||
|
||||
#define AXGBE_SFP_BASE_1GBE_CC 6
|
||||
#define AXGBE_SFP_BASE_1GBE_CC_SX BIT(0)
|
||||
#define AXGBE_SFP_BASE_1GBE_CC_LX BIT(1)
|
||||
#define AXGBE_SFP_BASE_1GBE_CC_CX BIT(2)
|
||||
#define AXGBE_SFP_BASE_1GBE_CC_T BIT(3)
|
||||
|
||||
#define AXGBE_SFP_BASE_CABLE 8
|
||||
#define AXGBE_SFP_BASE_CABLE_PASSIVE BIT(2)
|
||||
#define AXGBE_SFP_BASE_CABLE_ACTIVE BIT(3)
|
||||
|
||||
#define AXGBE_SFP_BASE_BR 12
|
||||
#define AXGBE_SFP_BASE_BR_1GBE_MIN 0x0a
|
||||
#define AXGBE_SFP_BASE_BR_1GBE_MAX 0x0d
|
||||
#define AXGBE_SFP_BASE_BR_10GBE_MIN 0x64
|
||||
#define AXGBE_SFP_BASE_BR_10GBE_MAX 0x68
|
||||
|
||||
#define AXGBE_SFP_BASE_CU_CABLE_LEN 18
|
||||
|
||||
#define AXGBE_SFP_BASE_VENDOR_NAME 20
|
||||
#define AXGBE_SFP_BASE_VENDOR_NAME_LEN 16
|
||||
#define AXGBE_SFP_BASE_VENDOR_PN 40
|
||||
#define AXGBE_SFP_BASE_VENDOR_PN_LEN 16
|
||||
#define AXGBE_SFP_BASE_VENDOR_REV 56
|
||||
#define AXGBE_SFP_BASE_VENDOR_REV_LEN 4
|
||||
|
||||
#define AXGBE_SFP_BASE_CC 63
|
||||
|
||||
/* SFP Serial ID Extended ID values relative to an offset of 64 */
|
||||
#define AXGBE_SFP_BASE_VENDOR_SN 4
|
||||
#define AXGBE_SFP_BASE_VENDOR_SN_LEN 16
|
||||
|
||||
#define AXGBE_SFP_EXTD_DIAG 28
|
||||
#define AXGBE_SFP_EXTD_DIAG_ADDR_CHANGE BIT(2)
|
||||
|
||||
#define AXGBE_SFP_EXTD_SFF_8472 30
|
||||
|
||||
#define AXGBE_SFP_EXTD_CC 31
|
||||
|
||||
struct axgbe_sfp_eeprom {
|
||||
u8 base[64];
|
||||
u8 extd[32];
|
||||
u8 vendor[32];
|
||||
};
|
||||
|
||||
#define AXGBE_BEL_FUSE_VENDOR "BEL-FUSE"
|
||||
#define AXGBE_BEL_FUSE_PARTNO "1GBT-SFP06"
|
||||
|
||||
struct axgbe_sfp_ascii {
|
||||
union {
|
||||
char vendor[AXGBE_SFP_BASE_VENDOR_NAME_LEN + 1];
|
||||
char partno[AXGBE_SFP_BASE_VENDOR_PN_LEN + 1];
|
||||
char rev[AXGBE_SFP_BASE_VENDOR_REV_LEN + 1];
|
||||
char serno[AXGBE_SFP_BASE_VENDOR_SN_LEN + 1];
|
||||
} u;
|
||||
};
|
||||
|
||||
/* MDIO PHY reset types */
|
||||
enum axgbe_mdio_reset {
|
||||
AXGBE_MDIO_RESET_NONE = 0,
|
||||
AXGBE_MDIO_RESET_I2C_GPIO,
|
||||
AXGBE_MDIO_RESET_INT_GPIO,
|
||||
AXGBE_MDIO_RESET_MAX,
|
||||
};
|
||||
|
||||
/* Re-driver related definitions */
|
||||
enum axgbe_phy_redrv_if {
|
||||
AXGBE_PHY_REDRV_IF_MDIO = 0,
|
||||
AXGBE_PHY_REDRV_IF_I2C,
|
||||
AXGBE_PHY_REDRV_IF_MAX,
|
||||
};
|
||||
|
||||
enum axgbe_phy_redrv_model {
|
||||
AXGBE_PHY_REDRV_MODEL_4223 = 0,
|
||||
AXGBE_PHY_REDRV_MODEL_4227,
|
||||
AXGBE_PHY_REDRV_MODEL_MAX,
|
||||
};
|
||||
|
||||
enum axgbe_phy_redrv_mode {
|
||||
AXGBE_PHY_REDRV_MODE_CX = 5,
|
||||
AXGBE_PHY_REDRV_MODE_SR = 9,
|
||||
};
|
||||
|
||||
#define AXGBE_PHY_REDRV_MODE_REG 0x12b0
|
||||
|
||||
/* PHY related configuration information */
|
||||
struct axgbe_phy_data {
|
||||
enum axgbe_port_mode port_mode;
|
||||
|
||||
unsigned int port_id;
|
||||
|
||||
unsigned int port_speeds;
|
||||
|
||||
enum axgbe_conn_type conn_type;
|
||||
|
||||
enum axgbe_mode cur_mode;
|
||||
enum axgbe_mode start_mode;
|
||||
|
||||
unsigned int rrc_count;
|
||||
|
||||
unsigned int mdio_addr;
|
||||
|
||||
unsigned int comm_owned;
|
||||
|
||||
/* SFP Support */
|
||||
enum axgbe_sfp_comm sfp_comm;
|
||||
unsigned int sfp_mux_address;
|
||||
unsigned int sfp_mux_channel;
|
||||
|
||||
unsigned int sfp_gpio_address;
|
||||
unsigned int sfp_gpio_mask;
|
||||
unsigned int sfp_gpio_rx_los;
|
||||
unsigned int sfp_gpio_tx_fault;
|
||||
unsigned int sfp_gpio_mod_absent;
|
||||
unsigned int sfp_gpio_rate_select;
|
||||
|
||||
unsigned int sfp_rx_los;
|
||||
unsigned int sfp_tx_fault;
|
||||
unsigned int sfp_mod_absent;
|
||||
unsigned int sfp_diags;
|
||||
unsigned int sfp_changed;
|
||||
unsigned int sfp_phy_avail;
|
||||
unsigned int sfp_cable_len;
|
||||
enum axgbe_sfp_base sfp_base;
|
||||
enum axgbe_sfp_cable sfp_cable;
|
||||
enum axgbe_sfp_speed sfp_speed;
|
||||
struct axgbe_sfp_eeprom sfp_eeprom;
|
||||
|
||||
/* External PHY support */
|
||||
enum axgbe_mdio_mode phydev_mode;
|
||||
enum axgbe_mdio_reset mdio_reset;
|
||||
unsigned int mdio_reset_addr;
|
||||
unsigned int mdio_reset_gpio;
|
||||
|
||||
/* Re-driver support */
|
||||
unsigned int redrv;
|
||||
unsigned int redrv_if;
|
||||
unsigned int redrv_addr;
|
||||
unsigned int redrv_lane;
|
||||
unsigned int redrv_model;
|
||||
};
|
||||
|
||||
static void axgbe_phy_sfp_gpio_setup(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_phy_data *phy_data = pdata->phy_data;
|
||||
unsigned int reg;
|
||||
|
||||
reg = XP_IOREAD(pdata, XP_PROP_3);
|
||||
|
||||
phy_data->sfp_gpio_address = AXGBE_GPIO_ADDRESS_PCA9555 +
|
||||
XP_GET_BITS(reg, XP_PROP_3, GPIO_ADDR);
|
||||
|
||||
phy_data->sfp_gpio_mask = XP_GET_BITS(reg, XP_PROP_3, GPIO_MASK);
|
||||
|
||||
phy_data->sfp_gpio_rx_los = XP_GET_BITS(reg, XP_PROP_3,
|
||||
GPIO_RX_LOS);
|
||||
phy_data->sfp_gpio_tx_fault = XP_GET_BITS(reg, XP_PROP_3,
|
||||
GPIO_TX_FAULT);
|
||||
phy_data->sfp_gpio_mod_absent = XP_GET_BITS(reg, XP_PROP_3,
|
||||
GPIO_MOD_ABS);
|
||||
phy_data->sfp_gpio_rate_select = XP_GET_BITS(reg, XP_PROP_3,
|
||||
GPIO_RATE_SELECT);
|
||||
}
|
||||
|
||||
static void axgbe_phy_sfp_comm_setup(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_phy_data *phy_data = pdata->phy_data;
|
||||
unsigned int reg, mux_addr_hi, mux_addr_lo;
|
||||
|
||||
reg = XP_IOREAD(pdata, XP_PROP_4);
|
||||
|
||||
mux_addr_hi = XP_GET_BITS(reg, XP_PROP_4, MUX_ADDR_HI);
|
||||
mux_addr_lo = XP_GET_BITS(reg, XP_PROP_4, MUX_ADDR_LO);
|
||||
if (mux_addr_lo == AXGBE_SFP_DIRECT)
|
||||
return;
|
||||
|
||||
phy_data->sfp_comm = AXGBE_SFP_COMM_PCA9545;
|
||||
phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo;
|
||||
phy_data->sfp_mux_channel = XP_GET_BITS(reg, XP_PROP_4, MUX_CHAN);
|
||||
}
|
||||
|
||||
static void axgbe_phy_sfp_setup(struct axgbe_port *pdata)
|
||||
{
|
||||
axgbe_phy_sfp_comm_setup(pdata);
|
||||
axgbe_phy_sfp_gpio_setup(pdata);
|
||||
}
|
||||
|
||||
static bool axgbe_phy_redrv_error(struct axgbe_phy_data *phy_data)
|
||||
{
|
||||
if (!phy_data->redrv)
|
||||
return false;
|
||||
|
||||
if (phy_data->redrv_if >= AXGBE_PHY_REDRV_IF_MAX)
|
||||
return true;
|
||||
|
||||
switch (phy_data->redrv_model) {
|
||||
case AXGBE_PHY_REDRV_MODEL_4223:
|
||||
if (phy_data->redrv_lane > 3)
|
||||
return true;
|
||||
break;
|
||||
case AXGBE_PHY_REDRV_MODEL_4227:
|
||||
if (phy_data->redrv_lane > 1)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int axgbe_phy_mdio_reset_setup(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_phy_data *phy_data = pdata->phy_data;
|
||||
unsigned int reg;
|
||||
|
||||
if (phy_data->conn_type != AXGBE_CONN_TYPE_MDIO)
|
||||
return 0;
|
||||
reg = XP_IOREAD(pdata, XP_PROP_3);
|
||||
phy_data->mdio_reset = XP_GET_BITS(reg, XP_PROP_3, MDIO_RESET);
|
||||
switch (phy_data->mdio_reset) {
|
||||
case AXGBE_MDIO_RESET_NONE:
|
||||
case AXGBE_MDIO_RESET_I2C_GPIO:
|
||||
case AXGBE_MDIO_RESET_INT_GPIO:
|
||||
break;
|
||||
default:
|
||||
PMD_DRV_LOG(ERR, "unsupported MDIO reset (%#x)\n",
|
||||
phy_data->mdio_reset);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (phy_data->mdio_reset == AXGBE_MDIO_RESET_I2C_GPIO) {
|
||||
phy_data->mdio_reset_addr = AXGBE_GPIO_ADDRESS_PCA9555 +
|
||||
XP_GET_BITS(reg, XP_PROP_3,
|
||||
MDIO_RESET_I2C_ADDR);
|
||||
phy_data->mdio_reset_gpio = XP_GET_BITS(reg, XP_PROP_3,
|
||||
MDIO_RESET_I2C_GPIO);
|
||||
} else if (phy_data->mdio_reset == AXGBE_MDIO_RESET_INT_GPIO) {
|
||||
phy_data->mdio_reset_gpio = XP_GET_BITS(reg, XP_PROP_3,
|
||||
MDIO_RESET_INT_GPIO);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool axgbe_phy_port_mode_mismatch(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_phy_data *phy_data = pdata->phy_data;
|
||||
|
||||
switch (phy_data->port_mode) {
|
||||
case AXGBE_PORT_MODE_BACKPLANE:
|
||||
if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000))
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_BACKPLANE_2500:
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_2500)
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_1000BASE_T:
|
||||
if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000))
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_1000BASE_X:
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000)
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_NBASE_T:
|
||||
if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_2500))
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_10GBASE_T:
|
||||
if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000))
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_10GBASE_R:
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000)
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_SFP:
|
||||
if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
|
||||
(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool axgbe_phy_conn_type_mismatch(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_phy_data *phy_data = pdata->phy_data;
|
||||
|
||||
switch (phy_data->port_mode) {
|
||||
case AXGBE_PORT_MODE_BACKPLANE:
|
||||
case AXGBE_PORT_MODE_BACKPLANE_2500:
|
||||
if (phy_data->conn_type == AXGBE_CONN_TYPE_BACKPLANE)
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_1000BASE_T:
|
||||
case AXGBE_PORT_MODE_1000BASE_X:
|
||||
case AXGBE_PORT_MODE_NBASE_T:
|
||||
case AXGBE_PORT_MODE_10GBASE_T:
|
||||
case AXGBE_PORT_MODE_10GBASE_R:
|
||||
if (phy_data->conn_type == AXGBE_CONN_TYPE_MDIO)
|
||||
return false;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_SFP:
|
||||
if (phy_data->conn_type == AXGBE_CONN_TYPE_SFP)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool axgbe_phy_port_enabled(struct axgbe_port *pdata)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = XP_IOREAD(pdata, XP_PROP_0);
|
||||
if (!XP_GET_BITS(reg, XP_PROP_0, PORT_SPEEDS))
|
||||
return false;
|
||||
if (!XP_GET_BITS(reg, XP_PROP_0, CONN_TYPE))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int axgbe_phy_init(struct axgbe_port *pdata)
|
||||
{
|
||||
struct axgbe_phy_data *phy_data;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
/* Check if enabled */
|
||||
if (!axgbe_phy_port_enabled(pdata)) {
|
||||
PMD_DRV_LOG(ERR, "device is not enabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Initialize the I2C controller */
|
||||
ret = pdata->i2c_if.i2c_init(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy_data = rte_zmalloc("phy_data memory", sizeof(*phy_data), 0);
|
||||
if (!phy_data) {
|
||||
PMD_DRV_LOG(ERR, "phy_data allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
pdata->phy_data = phy_data;
|
||||
|
||||
reg = XP_IOREAD(pdata, XP_PROP_0);
|
||||
phy_data->port_mode = XP_GET_BITS(reg, XP_PROP_0, PORT_MODE);
|
||||
phy_data->port_id = XP_GET_BITS(reg, XP_PROP_0, PORT_ID);
|
||||
phy_data->port_speeds = XP_GET_BITS(reg, XP_PROP_0, PORT_SPEEDS);
|
||||
phy_data->conn_type = XP_GET_BITS(reg, XP_PROP_0, CONN_TYPE);
|
||||
phy_data->mdio_addr = XP_GET_BITS(reg, XP_PROP_0, MDIO_ADDR);
|
||||
|
||||
reg = XP_IOREAD(pdata, XP_PROP_4);
|
||||
phy_data->redrv = XP_GET_BITS(reg, XP_PROP_4, REDRV_PRESENT);
|
||||
phy_data->redrv_if = XP_GET_BITS(reg, XP_PROP_4, REDRV_IF);
|
||||
phy_data->redrv_addr = XP_GET_BITS(reg, XP_PROP_4, REDRV_ADDR);
|
||||
phy_data->redrv_lane = XP_GET_BITS(reg, XP_PROP_4, REDRV_LANE);
|
||||
phy_data->redrv_model = XP_GET_BITS(reg, XP_PROP_4, REDRV_MODEL);
|
||||
|
||||
/* Validate the connection requested */
|
||||
if (axgbe_phy_conn_type_mismatch(pdata)) {
|
||||
PMD_DRV_LOG(ERR, "phy mode/connection mismatch (%#x/%#x)\n",
|
||||
phy_data->port_mode, phy_data->conn_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate the mode requested */
|
||||
if (axgbe_phy_port_mode_mismatch(pdata)) {
|
||||
PMD_DRV_LOG(ERR, "phy mode/speed mismatch (%#x/%#x)\n",
|
||||
phy_data->port_mode, phy_data->port_speeds);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for and validate MDIO reset support */
|
||||
ret = axgbe_phy_mdio_reset_setup(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Validate the re-driver information */
|
||||
if (axgbe_phy_redrv_error(phy_data)) {
|
||||
PMD_DRV_LOG(ERR, "phy re-driver settings error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pdata->kr_redrv = phy_data->redrv;
|
||||
|
||||
/* Indicate current mode is unknown */
|
||||
phy_data->cur_mode = AXGBE_MODE_UNKNOWN;
|
||||
|
||||
/* Initialize supported features */
|
||||
pdata->phy.supported = 0;
|
||||
|
||||
switch (phy_data->port_mode) {
|
||||
/* Backplane support */
|
||||
case AXGBE_PORT_MODE_BACKPLANE:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_Backplane;
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
|
||||
pdata->phy.supported |= SUPPORTED_1000baseKX_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_KX_1000;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) {
|
||||
pdata->phy.supported |= SUPPORTED_10000baseKR_Full;
|
||||
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
|
||||
pdata->phy.supported |=
|
||||
SUPPORTED_10000baseR_FEC;
|
||||
phy_data->start_mode = AXGBE_MODE_KR;
|
||||
}
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
|
||||
break;
|
||||
case AXGBE_PORT_MODE_BACKPLANE_2500:
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_Backplane;
|
||||
pdata->phy.supported |= SUPPORTED_2500baseX_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_KX_2500;
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
|
||||
break;
|
||||
|
||||
/* MDIO 1GBase-T support */
|
||||
case AXGBE_PORT_MODE_1000BASE_T:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_TP;
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
|
||||
pdata->phy.supported |= SUPPORTED_100baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_100;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
|
||||
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_1000;
|
||||
}
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_CL22;
|
||||
break;
|
||||
|
||||
/* MDIO Base-X support */
|
||||
case AXGBE_PORT_MODE_1000BASE_X:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_FIBRE;
|
||||
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_X;
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_CL22;
|
||||
break;
|
||||
|
||||
/* MDIO NBase-T support */
|
||||
case AXGBE_PORT_MODE_NBASE_T:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_TP;
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
|
||||
pdata->phy.supported |= SUPPORTED_100baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_100;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
|
||||
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_1000;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_2500) {
|
||||
pdata->phy.supported |= SUPPORTED_2500baseX_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_KX_2500;
|
||||
}
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_CL45;
|
||||
break;
|
||||
|
||||
/* 10GBase-T support */
|
||||
case AXGBE_PORT_MODE_10GBASE_T:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_TP;
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
|
||||
pdata->phy.supported |= SUPPORTED_100baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_100;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
|
||||
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_1000;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) {
|
||||
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_KR;
|
||||
}
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
|
||||
break;
|
||||
|
||||
/* 10GBase-R support */
|
||||
case AXGBE_PORT_MODE_10GBASE_R:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_TP;
|
||||
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
|
||||
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
|
||||
pdata->phy.supported |= SUPPORTED_10000baseR_FEC;
|
||||
phy_data->start_mode = AXGBE_MODE_SFI;
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
|
||||
break;
|
||||
|
||||
/* SFP support */
|
||||
case AXGBE_PORT_MODE_SFP:
|
||||
pdata->phy.supported |= SUPPORTED_Autoneg;
|
||||
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
pdata->phy.supported |= SUPPORTED_TP;
|
||||
pdata->phy.supported |= SUPPORTED_FIBRE;
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
|
||||
pdata->phy.supported |= SUPPORTED_100baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_100;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
|
||||
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SGMII_1000;
|
||||
}
|
||||
if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) {
|
||||
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
|
||||
phy_data->start_mode = AXGBE_MODE_SFI;
|
||||
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
|
||||
pdata->phy.supported |=
|
||||
SUPPORTED_10000baseR_FEC;
|
||||
}
|
||||
|
||||
phy_data->phydev_mode = AXGBE_MDIO_MODE_CL22;
|
||||
|
||||
axgbe_phy_sfp_setup(pdata);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((phy_data->conn_type & AXGBE_CONN_TYPE_MDIO) &&
|
||||
(phy_data->phydev_mode != AXGBE_MDIO_MODE_NONE)) {
|
||||
ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr,
|
||||
phy_data->phydev_mode);
|
||||
if (ret) {
|
||||
PMD_DRV_LOG(ERR, "mdio port/clause not compatible (%d/%u)\n",
|
||||
phy_data->mdio_addr, phy_data->phydev_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (phy_data->redrv && !phy_data->redrv_if) {
|
||||
ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr,
|
||||
AXGBE_MDIO_MODE_CL22);
|
||||
if (ret) {
|
||||
PMD_DRV_LOG(ERR, "redriver mdio port not compatible (%u)\n",
|
||||
phy_data->redrv_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void axgbe_init_function_ptrs_phy_v2(struct axgbe_phy_if *phy_if)
|
||||
{
|
||||
struct axgbe_phy_impl_if *phy_impl = &phy_if->phy_impl;
|
||||
|
||||
phy_impl->init = axgbe_phy_init;
|
||||
}
|
Loading…
Reference in New Issue
Block a user