Skip to content

Commit

Permalink
net: mvpp2: convert to phylink pcs operations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Russell King authored and David S. Miller committed Sep 3, 2020
1 parent 82b1c8f commit 94bfe43
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 116 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/marvell/mvpp2/mvpp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
292 changes: 176 additions & 116 deletions drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);

Expand All @@ -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
Expand All @@ -5621,28 +5694,13 @@ 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
* speed of 1000/2500Mbps in full duplex, so force 1000/2500
* 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)
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 94bfe43

Please sign in to comment.