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:
Ravi Kumar 2018-04-06 08:36:38 -04:00 committed by Ferruh Yigit
parent 572890ef66
commit 4ac7516b8b
7 changed files with 1463 additions and 0 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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_ */

View 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;
}

View 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;
}

View 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;
}