[lkml]   [2019]   [Dec]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    Subject[PATCH 4.19 039/321] net: bcmgenet: use RGMII loopback for MAC reset
    From: Doug Berger <>

    [ Upstream commit 3a55402c93877d291b0a612d25edb03d1b4b93ac ]

    As noted in commit 28c2d1a7a0bf ("net: bcmgenet: enable loopback
    during UniMAC sw_reset") the UniMAC must be clocked while sw_reset
    is asserted for its state machines to reset cleanly.

    The transmit and receive clocks used by the UniMAC are derived from
    the signals used on its PHY interface. The bcmgenet MAC can be
    configured to work with different PHY interfaces including MII,
    GMII, RGMII, and Reverse MII on internal and external interfaces.
    Unfortunately for the UniMAC, when configured for MII the Tx clock
    is always driven from the PHY which places it outside of the direct
    control of the MAC.

    The earlier commit enabled a local loopback mode within the UniMAC
    so that the receive clock would be derived from the transmit clock
    which addressed the observed issue with an external GPHY disabling
    it's Rx clock. However, when a Tx clock is not available this
    loopback is insufficient.

    This commit implements a workaround that leverages the fact that
    the MAC can reliably generate all of its necessary clocking by
    enterring the external GPHY RGMII interface mode with the UniMAC in
    local loopback during the sw_reset interval. Unfortunately, this
    has the undesirable side efect of the RGMII GTXCLK signal being
    driven during the same window.

    In most configurations this is a benign side effect as the signal
    is either not routed to a pin or is already expected to drive the
    pin. The one exception is when an external MII PHY is expected to
    drive the same pin with its TX_CLK output creating output driver

    This commit exploits the IEEE 802.3 clause 22 standard defined
    isolate mode to force an external MII PHY to present a high
    impedance on its TX_CLK output during the window to prevent any
    contention at the pin.

    The MII interface is used internally with the 40nm internal EPHY
    which agressively disables its clocks for power savings leading to
    incomplete resets of the UniMAC and many instabilities observed
    over the years. The workaround of this commit is expected to put
    an end to those problems.

    Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
    Signed-off-by: Doug Berger <>
    Acked-by: Florian Fainelli <>
    Signed-off-by: David S. Miller <>
    Signed-off-by: Sasha Levin <>
    .../net/ethernet/broadcom/genet/bcmgenet.c | 2 --
    drivers/net/ethernet/broadcom/genet/bcmmii.c | 33 +++++++++++++++++++
    2 files changed, 33 insertions(+), 2 deletions(-)

    diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
    index 338d223804343..6f7278d2ce4f2 100644
    --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
    +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
    @@ -1998,8 +1998,6 @@ static void reset_umac(struct bcmgenet_priv *priv)

    /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */
    bcmgenet_umac_writel(priv, CMD_SW_RESET | CMD_LCL_LOOP_EN, UMAC_CMD);
    - udelay(2);
    - bcmgenet_umac_writel(priv, 0, UMAC_CMD);

    static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
    diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
    index b0592fd4135b3..a5049d637791d 100644
    --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
    +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
    @@ -184,8 +184,38 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
    const char *phy_name = NULL;
    u32 id_mode_dis = 0;
    u32 port_ctrl;
    + int bmcr = -1;
    + int ret;
    u32 reg;

    + /* MAC clocking workaround during reset of umac state machines */
    + reg = bcmgenet_umac_readl(priv, UMAC_CMD);
    + if (reg & CMD_SW_RESET) {
    + /* An MII PHY must be isolated to prevent TXC contention */
    + if (priv->phy_interface == PHY_INTERFACE_MODE_MII) {
    + ret = phy_read(phydev, MII_BMCR);
    + if (ret >= 0) {
    + bmcr = ret;
    + ret = phy_write(phydev, MII_BMCR,
    + bmcr | BMCR_ISOLATE);
    + }
    + if (ret) {
    + netdev_err(dev, "failed to isolate PHY\n");
    + return ret;
    + }
    + }
    + /* Switch MAC clocking to RGMII generated clock */
    + bcmgenet_sys_writel(priv, PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
    + /* Ensure 5 clks with Rx disabled
    + * followed by 5 clks with Reset asserted
    + */
    + udelay(4);
    + reg &= ~(CMD_SW_RESET | CMD_LCL_LOOP_EN);
    + bcmgenet_umac_writel(priv, reg, UMAC_CMD);
    + /* Ensure 5 more clocks before Rx is enabled */
    + udelay(2);
    + }
    priv->ext_phy = !priv->internal_phy &&
    (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);

    @@ -217,6 +247,9 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
    phydev->supported &= PHY_BASIC_FEATURES;
    + /* Restore the MII PHY after isolation */
    + if (bmcr >= 0)
    + phy_write(phydev, MII_BMCR, bmcr);


     \ /
      Last update: 2019-12-03 23:47    [W:13.546 / U:3.624 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site