net: mvpp2: convert to phylink pcs operations

Convert mvpp2 to phylink's new pcs support.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Russell King 2020-09-01 14:48:32 +01:00 committed by David S. Miller
parent 82b1c8fae8
commit 94bfe438bc
2 changed files with 177 additions and 116 deletions

View File

@ -967,6 +967,7 @@ struct mvpp2_port {
phy_interface_t phy_interface;
struct phylink *phylink;
struct phylink_config phylink_config;
struct phylink_pcs phylink_pcs;
struct phy *comphy;
struct mvpp2_bm_pool *pool_long;

View File

@ -1479,8 +1479,8 @@ static void mvpp2_port_loopback_set(struct mvpp2_port *port,
else
val &= ~MVPP2_GMAC_GMII_LB_EN_MASK;
if (phy_interface_mode_is_8023z(port->phy_interface) ||
port->phy_interface == PHY_INTERFACE_MODE_SGMII)
if (phy_interface_mode_is_8023z(state->interface) ||
state->interface == PHY_INTERFACE_MODE_SGMII)
val |= MVPP2_GMAC_PCS_LB_EN_MASK;
else
val &= ~MVPP2_GMAC_PCS_LB_EN_MASK;
@ -5376,6 +5376,174 @@ static struct mvpp2_port *mvpp2_phylink_to_port(struct phylink_config *config)
return container_of(config, struct mvpp2_port, phylink_config);
}
static struct mvpp2_port *mvpp2_pcs_to_port(struct phylink_pcs *pcs)
{
return container_of(pcs, struct mvpp2_port, phylink_pcs);
}
static void mvpp22_xlg_pcs_get_state(struct mvpp2_port *port,
struct phylink_link_state *state)
{
u32 val;
state->speed = SPEED_10000;
state->duplex = 1;
state->an_complete = 1;
val = readl(port->base + MVPP22_XLG_STATUS);
state->link = !!(val & MVPP22_XLG_STATUS_LINK_UP);
state->pause = 0;
val = readl(port->base + MVPP22_XLG_CTRL0_REG);
if (val & MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN)
state->pause |= MLO_PAUSE_TX;
if (val & MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN)
state->pause |= MLO_PAUSE_RX;
}
static void mvpp2_gmac_pcs_get_state(struct mvpp2_port *port,
struct phylink_link_state *state)
{
u32 val;
val = readl(port->base + MVPP2_GMAC_STATUS0);
state->an_complete = !!(val & MVPP2_GMAC_STATUS0_AN_COMPLETE);
state->link = !!(val & MVPP2_GMAC_STATUS0_LINK_UP);
state->duplex = !!(val & MVPP2_GMAC_STATUS0_FULL_DUPLEX);
switch (port->phy_interface) {
case PHY_INTERFACE_MODE_1000BASEX:
state->speed = SPEED_1000;
break;
case PHY_INTERFACE_MODE_2500BASEX:
state->speed = SPEED_2500;
break;
default:
if (val & MVPP2_GMAC_STATUS0_GMII_SPEED)
state->speed = SPEED_1000;
else if (val & MVPP2_GMAC_STATUS0_MII_SPEED)
state->speed = SPEED_100;
else
state->speed = SPEED_10;
}
state->pause = 0;
if (val & MVPP2_GMAC_STATUS0_RX_PAUSE)
state->pause |= MLO_PAUSE_RX;
if (val & MVPP2_GMAC_STATUS0_TX_PAUSE)
state->pause |= MLO_PAUSE_TX;
}
static void mvpp2_phylink_pcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
{
struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
mode &= MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
if (mode == MVPP22_XLG_CTRL3_MACMODESELECT_10G) {
mvpp22_xlg_pcs_get_state(port, state);
return;
}
}
mvpp2_gmac_pcs_get_state(port, state);
}
static int mvpp2_gmac_pcs_config(struct mvpp2_port *port, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertising,
bool permit_pause_to_mac)
{
u32 mask, val, an, old_an, changed;
mask = MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS |
MVPP2_GMAC_IN_BAND_AUTONEG |
MVPP2_GMAC_AN_SPEED_EN |
MVPP2_GMAC_FLOW_CTRL_AUTONEG |
MVPP2_GMAC_AN_DUPLEX_EN;
if (phylink_autoneg_inband(mode)) {
mask |= MVPP2_GMAC_CONFIG_MII_SPEED |
MVPP2_GMAC_CONFIG_GMII_SPEED |
MVPP2_GMAC_CONFIG_FULL_DUPLEX;
val = MVPP2_GMAC_IN_BAND_AUTONEG;
if (interface == PHY_INTERFACE_MODE_SGMII) {
/* SGMII mode receives the speed and duplex from PHY */
val |= MVPP2_GMAC_AN_SPEED_EN |
MVPP2_GMAC_AN_DUPLEX_EN;
} else {
/* 802.3z mode has fixed speed and duplex */
val |= MVPP2_GMAC_CONFIG_GMII_SPEED |
MVPP2_GMAC_CONFIG_FULL_DUPLEX;
/* The FLOW_CTRL_AUTONEG bit selects either the hardware
* automatically or the bits in MVPP22_GMAC_CTRL_4_REG
* manually controls the GMAC pause modes.
*/
if (permit_pause_to_mac)
val |= MVPP2_GMAC_FLOW_CTRL_AUTONEG;
/* Configure advertisement bits */
mask |= MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN;
if (phylink_test(advertising, Pause))
val |= MVPP2_GMAC_FC_ADV_EN;
if (phylink_test(advertising, Asym_Pause))
val |= MVPP2_GMAC_FC_ADV_ASM_EN;
}
} else {
val = 0;
}
old_an = an = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
an = (an & ~mask) | val;
changed = an ^ old_an;
if (changed)
writel(an, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
/* We are only interested in the advertisement bits changing */
return changed & (MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN);
}
static int mvpp2_phylink_pcs_config(struct phylink_pcs *pcs,
unsigned int mode,
phy_interface_t interface,
const unsigned long *advertising,
bool permit_pause_to_mac)
{
struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
int ret;
if (mvpp2_is_xlg(interface))
ret = 0;
else
ret = mvpp2_gmac_pcs_config(port, mode, interface, advertising,
permit_pause_to_mac);
return ret;
}
static void mvpp2_phylink_pcs_an_restart(struct phylink_pcs *pcs)
{
struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
port->base + MVPP2_GMAC_AUTONEG_CONFIG);
writel(val & ~MVPP2_GMAC_IN_BAND_RESTART_AN,
port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
static const struct phylink_pcs_ops mvpp2_phylink_pcs_ops = {
.pcs_get_state = mvpp2_phylink_pcs_get_state,
.pcs_config = mvpp2_phylink_pcs_config,
.pcs_an_restart = mvpp2_phylink_pcs_an_restart,
};
static void mvpp2_phylink_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
@ -5464,89 +5632,6 @@ static void mvpp2_phylink_validate(struct phylink_config *config,
bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
}
static void mvpp22_xlg_pcs_get_state(struct mvpp2_port *port,
struct phylink_link_state *state)
{
u32 val;
state->speed = SPEED_10000;
state->duplex = 1;
state->an_complete = 1;
val = readl(port->base + MVPP22_XLG_STATUS);
state->link = !!(val & MVPP22_XLG_STATUS_LINK_UP);
state->pause = 0;
val = readl(port->base + MVPP22_XLG_CTRL0_REG);
if (val & MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN)
state->pause |= MLO_PAUSE_TX;
if (val & MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN)
state->pause |= MLO_PAUSE_RX;
}
static void mvpp2_gmac_pcs_get_state(struct mvpp2_port *port,
struct phylink_link_state *state)
{
u32 val;
val = readl(port->base + MVPP2_GMAC_STATUS0);
state->an_complete = !!(val & MVPP2_GMAC_STATUS0_AN_COMPLETE);
state->link = !!(val & MVPP2_GMAC_STATUS0_LINK_UP);
state->duplex = !!(val & MVPP2_GMAC_STATUS0_FULL_DUPLEX);
switch (port->phy_interface) {
case PHY_INTERFACE_MODE_1000BASEX:
state->speed = SPEED_1000;
break;
case PHY_INTERFACE_MODE_2500BASEX:
state->speed = SPEED_2500;
break;
default:
if (val & MVPP2_GMAC_STATUS0_GMII_SPEED)
state->speed = SPEED_1000;
else if (val & MVPP2_GMAC_STATUS0_MII_SPEED)
state->speed = SPEED_100;
else
state->speed = SPEED_10;
}
state->pause = 0;
if (val & MVPP2_GMAC_STATUS0_RX_PAUSE)
state->pause |= MLO_PAUSE_RX;
if (val & MVPP2_GMAC_STATUS0_TX_PAUSE)
state->pause |= MLO_PAUSE_TX;
}
static void mvpp2_phylink_mac_pcs_get_state(struct phylink_config *config,
struct phylink_link_state *state)
{
struct mvpp2_port *port = mvpp2_phylink_to_port(config);
if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
mode &= MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
if (mode == MVPP22_XLG_CTRL3_MACMODESELECT_10G) {
mvpp22_xlg_pcs_get_state(port, state);
return;
}
}
mvpp2_gmac_pcs_get_state(port, state);
}
static void mvpp2_mac_an_restart(struct phylink_config *config)
{
struct mvpp2_port *port = mvpp2_phylink_to_port(config);
u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
port->base + MVPP2_GMAC_AUTONEG_CONFIG);
writel(val & ~MVPP2_GMAC_IN_BAND_RESTART_AN,
port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode,
const struct phylink_link_state *state)
{
@ -5570,20 +5655,14 @@ static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode,
static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
const struct phylink_link_state *state)
{
u32 old_an, an;
u32 old_ctrl0, ctrl0;
u32 old_ctrl2, ctrl2;
u32 old_ctrl4, ctrl4;
old_an = an = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
old_ctrl0 = ctrl0 = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
old_ctrl2 = ctrl2 = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
old_ctrl4 = ctrl4 = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
an &= ~(MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FC_ADV_EN |
MVPP2_GMAC_FC_ADV_ASM_EN | MVPP2_GMAC_FLOW_CTRL_AUTONEG |
MVPP2_GMAC_AN_DUPLEX_EN | MVPP2_GMAC_IN_BAND_AUTONEG |
MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS);
ctrl0 &= ~MVPP2_GMAC_PORT_TYPE_MASK;
ctrl2 &= ~(MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PCS_ENABLE_MASK);
@ -5607,12 +5686,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
}
/* Configure advertisement bits */
if (phylink_test(state->advertising, Pause))
an |= MVPP2_GMAC_FC_ADV_EN;
if (phylink_test(state->advertising, Asym_Pause))
an |= MVPP2_GMAC_FC_ADV_ASM_EN;
/* Configure negotiation style */
if (!phylink_autoneg_inband(mode)) {
/* Phy or fixed speed - no in-band AN, nothing to do, leave the
@ -5621,12 +5694,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
} else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
/* SGMII in-band mode receives the speed and duplex from
* the PHY. Flow control information is not received. */
an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
MVPP2_GMAC_CONFIG_GMII_SPEED |
MVPP2_GMAC_CONFIG_FULL_DUPLEX);
an |= MVPP2_GMAC_IN_BAND_AUTONEG |
MVPP2_GMAC_AN_SPEED_EN |
MVPP2_GMAC_AN_DUPLEX_EN;
} else if (phy_interface_mode_is_8023z(state->interface)) {
/* 1000BaseX and 2500BaseX ports cannot negotiate speed nor can
* they negotiate duplex: they are always operating with a fixed
@ -5634,15 +5701,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
* speed and full duplex here.
*/
ctrl0 |= MVPP2_GMAC_PORT_TYPE_MASK;
an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
MVPP2_GMAC_CONFIG_GMII_SPEED |
MVPP2_GMAC_CONFIG_FULL_DUPLEX);
an |= MVPP2_GMAC_IN_BAND_AUTONEG |
MVPP2_GMAC_CONFIG_GMII_SPEED |
MVPP2_GMAC_CONFIG_FULL_DUPLEX;
if (state->pause & MLO_PAUSE_AN && state->an_enabled)
an |= MVPP2_GMAC_FLOW_CTRL_AUTONEG;
}
if (old_ctrl0 != ctrl0)
@ -5651,8 +5709,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
writel(ctrl2, port->base + MVPP2_GMAC_CTRL_2_REG);
if (old_ctrl4 != ctrl4)
writel(ctrl4, port->base + MVPP22_GMAC_CTRL_4_REG);
if (old_an != an)
writel(an, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
static int mvpp2_mac_prepare(struct phylink_config *config, unsigned int mode,
@ -5861,8 +5917,6 @@ static void mvpp2_mac_link_down(struct phylink_config *config,
static const struct phylink_mac_ops mvpp2_phylink_ops = {
.validate = mvpp2_phylink_validate,
.mac_pcs_get_state = mvpp2_phylink_mac_pcs_get_state,
.mac_an_restart = mvpp2_mac_an_restart,
.mac_prepare = mvpp2_mac_prepare,
.mac_config = mvpp2_mac_config,
.mac_finish = mvpp2_mac_finish,
@ -5883,6 +5937,9 @@ static void mvpp2_acpi_start(struct mvpp2_port *port)
mvpp2_mac_prepare(&port->phylink_config, MLO_AN_INBAND,
port->phy_interface);
mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
mvpp2_phylink_pcs_config(&port->phylink_pcs, MLO_AN_INBAND,
port->phy_interface, state.advertising,
false);
mvpp2_mac_finish(&port->phylink_config, MLO_AN_INBAND,
port->phy_interface);
mvpp2_mac_link_up(&port->phylink_config, NULL,
@ -6114,6 +6171,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
goto err_free_port_pcpu;
}
port->phylink = phylink;
port->phylink_pcs.ops = &mvpp2_phylink_pcs_ops;
phylink_set_pcs(phylink, &port->phylink_pcs);
} else {
port->phylink = NULL;
}