|
|
|
@ -15,6 +15,7 @@
|
|
|
|
|
#define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0
|
|
|
|
|
#define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0
|
|
|
|
|
#define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0
|
|
|
|
|
#define SYNOPSYS_XPCS_SGMII_ID 0x7996ced0
|
|
|
|
|
#define SYNOPSYS_XPCS_MASK 0xffffffff
|
|
|
|
|
|
|
|
|
|
/* Vendor regs access */
|
|
|
|
@ -57,6 +58,34 @@
|
|
|
|
|
#define DW_C73_2500KX BIT(0)
|
|
|
|
|
#define DW_C73_5000KR BIT(1)
|
|
|
|
|
|
|
|
|
|
/* Clause 37 Defines */
|
|
|
|
|
/* VR MII MMD registers offsets */
|
|
|
|
|
#define DW_VR_MII_DIG_CTRL1 0x8000
|
|
|
|
|
#define DW_VR_MII_AN_CTRL 0x8001
|
|
|
|
|
#define DW_VR_MII_AN_INTR_STS 0x8002
|
|
|
|
|
|
|
|
|
|
/* VR_MII_DIG_CTRL1 */
|
|
|
|
|
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
|
|
|
|
|
|
|
|
|
|
/* VR_MII_AN_CTRL */
|
|
|
|
|
#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
|
|
|
|
|
#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0
|
|
|
|
|
#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
/* VR_MII_AN_INTR_STS */
|
|
|
|
|
#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)
|
|
|
|
|
#define DW_VR_MII_C37_ANSGM_SP_10 0x0
|
|
|
|
|
#define DW_VR_MII_C37_ANSGM_SP_100 0x1
|
|
|
|
|
#define DW_VR_MII_C37_ANSGM_SP_1000 0x2
|
|
|
|
|
#define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4)
|
|
|
|
|
|
|
|
|
|
static const int xpcs_usxgmii_features[] = {
|
|
|
|
|
ETHTOOL_LINK_MODE_Pause_BIT,
|
|
|
|
|
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
|
|
|
@ -105,6 +134,16 @@ static const int xpcs_xlgmii_features[] = {
|
|
|
|
|
__ETHTOOL_LINK_MODE_MASK_NBITS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const int xpcs_sgmii_features[] = {
|
|
|
|
|
ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
|
|
|
|
ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
|
|
|
|
ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
|
|
|
|
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
|
|
|
|
ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
|
|
|
|
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
|
|
|
|
__ETHTOOL_LINK_MODE_MASK_NBITS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const phy_interface_t xpcs_usxgmii_interfaces[] = {
|
|
|
|
|
PHY_INTERFACE_MODE_USXGMII,
|
|
|
|
|
PHY_INTERFACE_MODE_MAX,
|
|
|
|
@ -120,27 +159,42 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = {
|
|
|
|
|
PHY_INTERFACE_MODE_MAX,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const phy_interface_t xpcs_sgmii_interfaces[] = {
|
|
|
|
|
PHY_INTERFACE_MODE_SGMII,
|
|
|
|
|
PHY_INTERFACE_MODE_MAX,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct xpcs_id {
|
|
|
|
|
u32 id;
|
|
|
|
|
u32 mask;
|
|
|
|
|
const int *supported;
|
|
|
|
|
const phy_interface_t *interface;
|
|
|
|
|
int an_mode;
|
|
|
|
|
} xpcs_id_list[] = {
|
|
|
|
|
{
|
|
|
|
|
.id = SYNOPSYS_XPCS_USXGMII_ID,
|
|
|
|
|
.mask = SYNOPSYS_XPCS_MASK,
|
|
|
|
|
.supported = xpcs_usxgmii_features,
|
|
|
|
|
.interface = xpcs_usxgmii_interfaces,
|
|
|
|
|
.an_mode = DW_AN_C73,
|
|
|
|
|
}, {
|
|
|
|
|
.id = SYNOPSYS_XPCS_10GKR_ID,
|
|
|
|
|
.mask = SYNOPSYS_XPCS_MASK,
|
|
|
|
|
.supported = xpcs_10gkr_features,
|
|
|
|
|
.interface = xpcs_10gkr_interfaces,
|
|
|
|
|
.an_mode = DW_AN_C73,
|
|
|
|
|
}, {
|
|
|
|
|
.id = SYNOPSYS_XPCS_XLGMII_ID,
|
|
|
|
|
.mask = SYNOPSYS_XPCS_MASK,
|
|
|
|
|
.supported = xpcs_xlgmii_features,
|
|
|
|
|
.interface = xpcs_xlgmii_interfaces,
|
|
|
|
|
.an_mode = DW_AN_C73,
|
|
|
|
|
}, {
|
|
|
|
|
.id = SYNOPSYS_XPCS_SGMII_ID,
|
|
|
|
|
.mask = SYNOPSYS_XPCS_MASK,
|
|
|
|
|
.supported = xpcs_sgmii_features,
|
|
|
|
|
.interface = xpcs_sgmii_interfaces,
|
|
|
|
|
.an_mode = DW_AN_C37_SGMII,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -195,9 +249,20 @@ static int xpcs_poll_reset(struct mdio_xpcs_args *xpcs, int dev)
|
|
|
|
|
return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs, int dev)
|
|
|
|
|
static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
int ret, dev;
|
|
|
|
|
|
|
|
|
|
switch (xpcs->an_mode) {
|
|
|
|
|
case DW_AN_C73:
|
|
|
|
|
dev = MDIO_MMD_PCS;
|
|
|
|
|
break;
|
|
|
|
|
case DW_AN_C37_SGMII:
|
|
|
|
|
dev = MDIO_MMD_VEND2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET);
|
|
|
|
|
if (ret < 0)
|
|
|
|
@ -212,8 +277,8 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs, int dev)
|
|
|
|
|
dev_warn(&(__xpcs)->bus->dev, ##__args); \
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
static int xpcs_read_fault(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
static int xpcs_read_fault_c73(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
@ -263,7 +328,7 @@ static int xpcs_read_fault(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_read_link(struct mdio_xpcs_args *xpcs, bool an)
|
|
|
|
|
static int xpcs_read_link_c73(struct mdio_xpcs_args *xpcs, bool an)
|
|
|
|
|
{
|
|
|
|
|
bool link = true;
|
|
|
|
|
int ret;
|
|
|
|
@ -357,7 +422,7 @@ static int xpcs_config_usxgmii(struct mdio_xpcs_args *xpcs, int speed)
|
|
|
|
|
return xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
static int _xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
{
|
|
|
|
|
int ret, adv;
|
|
|
|
|
|
|
|
|
@ -401,11 +466,11 @@ static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_config_aneg(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = xpcs_config_aneg_c73(xpcs);
|
|
|
|
|
ret = _xpcs_config_aneg_c73(xpcs);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
@ -418,8 +483,8 @@ static int xpcs_config_aneg(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_aneg_done(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
static int xpcs_aneg_done_c73(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
@ -434,7 +499,7 @@ static int xpcs_aneg_done(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
|
|
|
|
|
/* Check if Aneg outcome is valid */
|
|
|
|
|
if (!(ret & DW_C73_AN_ADV_SF)) {
|
|
|
|
|
xpcs_config_aneg(xpcs);
|
|
|
|
|
xpcs_config_aneg_c73(xpcs);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -444,8 +509,8 @@ static int xpcs_aneg_done(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_read_lpa(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
static int xpcs_read_lpa_c73(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
@ -493,8 +558,8 @@ static int xpcs_read_lpa(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void xpcs_resolve_lpa(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
static void xpcs_resolve_lpa_c73(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
|
|
|
|
|
|
|
|
|
@ -585,15 +650,141 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* For AN for C37 SGMII mode, the settings are :-
|
|
|
|
|
* 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
|
|
|
|
|
* 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
|
|
|
|
|
* DW xPCS used with DW EQoS MAC is always MAC side SGMII.
|
|
|
|
|
* 3) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
|
|
|
|
|
* speed/duplex mode change by HW after SGMII AN complete)
|
|
|
|
|
*
|
|
|
|
|
* Note: Since it is MAC side SGMII, there is no need to set
|
|
|
|
|
* SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from
|
|
|
|
|
* PHY about the link state change after C28 AN is completed
|
|
|
|
|
* between PHY and Link Partner. There is also no need to
|
|
|
|
|
* trigger AN restart for MAC-side SGMII.
|
|
|
|
|
*/
|
|
|
|
|
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
|
|
|
|
|
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);
|
|
|
|
|
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
|
|
|
|
|
|
|
|
|
|
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_config(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
const struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (state->an_enabled) {
|
|
|
|
|
ret = xpcs_config_aneg(xpcs);
|
|
|
|
|
switch (xpcs->an_mode) {
|
|
|
|
|
case DW_AN_C73:
|
|
|
|
|
if (state->an_enabled) {
|
|
|
|
|
ret = xpcs_config_aneg_c73(xpcs);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case DW_AN_C37_SGMII:
|
|
|
|
|
ret = xpcs_config_aneg_c37_sgmii(xpcs);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Link needs to be read first ... */
|
|
|
|
|
state->link = xpcs_read_link_c73(xpcs, state->an_enabled) > 0 ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
/* ... and then we check the faults. */
|
|
|
|
|
ret = xpcs_read_fault_c73(xpcs, state);
|
|
|
|
|
if (ret) {
|
|
|
|
|
ret = xpcs_soft_reset(xpcs);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
state->link = 0;
|
|
|
|
|
|
|
|
|
|
return xpcs_config(xpcs, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state)) {
|
|
|
|
|
state->an_complete = true;
|
|
|
|
|
xpcs_read_lpa_c73(xpcs, state);
|
|
|
|
|
xpcs_resolve_lpa_c73(xpcs, state);
|
|
|
|
|
} else if (state->an_enabled) {
|
|
|
|
|
state->link = 0;
|
|
|
|
|
} else if (state->link) {
|
|
|
|
|
xpcs_resolve_pma(xpcs, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xpcs_get_state_c37_sgmii(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
struct phylink_link_state *state)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Reset link_state */
|
|
|
|
|
state->link = false;
|
|
|
|
|
state->speed = SPEED_UNKNOWN;
|
|
|
|
|
state->duplex = DUPLEX_UNKNOWN;
|
|
|
|
|
state->pause = 0;
|
|
|
|
|
|
|
|
|
|
/* For C37 SGMII mode, we check DW_VR_MII_AN_INTR_STS for link
|
|
|
|
|
* status, speed and duplex.
|
|
|
|
|
*/
|
|
|
|
|
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
|
|
|
|
|
int speed_value;
|
|
|
|
|
|
|
|
|
|
state->link = true;
|
|
|
|
|
|
|
|
|
|
speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >>
|
|
|
|
|
DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT;
|
|
|
|
|
if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000)
|
|
|
|
|
state->speed = SPEED_1000;
|
|
|
|
|
else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100)
|
|
|
|
|
state->speed = SPEED_100;
|
|
|
|
|
else
|
|
|
|
|
state->speed = SPEED_10;
|
|
|
|
|
|
|
|
|
|
if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD)
|
|
|
|
|
state->duplex = DUPLEX_FULL;
|
|
|
|
|
else
|
|
|
|
|
state->duplex = DUPLEX_HALF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -604,29 +795,19 @@ static int xpcs_get_state(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Link needs to be read first ... */
|
|
|
|
|
state->link = xpcs_read_link(xpcs, state->an_enabled) > 0 ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
/* ... and then we check the faults. */
|
|
|
|
|
ret = xpcs_read_fault(xpcs, state);
|
|
|
|
|
if (ret) {
|
|
|
|
|
ret = xpcs_soft_reset(xpcs, MDIO_MMD_PCS);
|
|
|
|
|
switch (xpcs->an_mode) {
|
|
|
|
|
case DW_AN_C73:
|
|
|
|
|
ret = xpcs_get_state_c73(xpcs, state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
state->link = 0;
|
|
|
|
|
|
|
|
|
|
return xpcs_config(xpcs, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state->an_enabled && xpcs_aneg_done(xpcs, state)) {
|
|
|
|
|
state->an_complete = true;
|
|
|
|
|
xpcs_read_lpa(xpcs, state);
|
|
|
|
|
xpcs_resolve_lpa(xpcs, state);
|
|
|
|
|
} else if (state->an_enabled) {
|
|
|
|
|
state->link = 0;
|
|
|
|
|
} else if (state->link) {
|
|
|
|
|
xpcs_resolve_pma(xpcs, state);
|
|
|
|
|
break;
|
|
|
|
|
case DW_AN_C37_SGMII:
|
|
|
|
|
ret = xpcs_get_state_c37_sgmii(xpcs, state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -646,6 +827,7 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
int ret;
|
|
|
|
|
u32 id;
|
|
|
|
|
|
|
|
|
|
/* First, search C73 PCS using PCS MMD */
|
|
|
|
|
ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return 0xffffffff;
|
|
|
|
@ -656,7 +838,26 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return 0xffffffff;
|
|
|
|
|
|
|
|
|
|
return id | ret;
|
|
|
|
|
/* If Device IDs are not all zeros, we found C73 AN-type device */
|
|
|
|
|
if (id | ret)
|
|
|
|
|
return id | ret;
|
|
|
|
|
|
|
|
|
|
/* Next, search C37 PCS using Vendor-Specific MII MMD */
|
|
|
|
|
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return 0xffffffff;
|
|
|
|
|
|
|
|
|
|
id = ret << 16;
|
|
|
|
|
|
|
|
|
|
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return 0xffffffff;
|
|
|
|
|
|
|
|
|
|
/* If Device IDs are not all zeros, we found C37 AN-type device */
|
|
|
|
|
if (id | ret)
|
|
|
|
|
return id | ret;
|
|
|
|
|
|
|
|
|
|
return 0xffffffff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool xpcs_check_features(struct mdio_xpcs_args *xpcs,
|
|
|
|
@ -676,6 +877,8 @@ static bool xpcs_check_features(struct mdio_xpcs_args *xpcs,
|
|
|
|
|
for (i = 0; match->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
|
|
|
|
|
set_bit(match->supported[i], xpcs->supported);
|
|
|
|
|
|
|
|
|
|
xpcs->an_mode = match->an_mode;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -692,7 +895,7 @@ static int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface)
|
|
|
|
|
match = entry;
|
|
|
|
|
|
|
|
|
|
if (xpcs_check_features(xpcs, match, interface))
|
|
|
|
|
return xpcs_soft_reset(xpcs, MDIO_MMD_PCS);
|
|
|
|
|
return xpcs_soft_reset(xpcs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|