Skip to content

Commit 1cff6ff

Browse files
paritoshd-nvPaolo Abeni
authored andcommitted
net: stmmac: dwmac-tegra: Fix link bring-up sequence
The Tegra MGBE driver sometimes fails to initialize, reporting the following error, and as a result, it is unable to acquire an IP address with DHCP: tegra-mgbe 6800000.ethernet: timeout waiting for link to become ready As per the recommendation from the Tegra hardware design team, fix this issue by: - clearing the PHY_RDY bit before setting the CDR_RESET bit and then setting PHY_RDY bit before clearing CDR_RESET bit. This ensures valid data is present at UPHY RX inputs before starting the CDR lock. - adding the required delays when bringing up the UPHY lane. Note we need to use delays here because there is no alternative, such as polling, for these cases. Using the usleep_range() instead of ndelay() as sleeping is preferred over busy wait loop. Without this change we would see link failures on boot sometimes as often as 1 in 5 boots. With this fix we have not observed any failures in over 1000 boots. Fixes: d8ca113 ("net: stmmac: tegra: Add MGBE support") Signed-off-by: Paritosh Dixit <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent b62f4c1 commit 1cff6ff

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,12 @@ static int mgbe_uphy_lane_bringup_serdes_up(struct net_device *ndev, void *mgbe_
127127
value &= ~XPCS_WRAP_UPHY_RX_CONTROL_AUX_RX_IDDQ;
128128
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
129129

130+
usleep_range(10, 20); /* 50ns min delay needed as per HW design */
130131
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
131132
value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_SLEEP;
132133
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
133134

135+
usleep_range(10, 20); /* 500ns min delay needed as per HW design */
134136
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
135137
value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_CAL_EN;
136138
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
@@ -143,22 +145,30 @@ static int mgbe_uphy_lane_bringup_serdes_up(struct net_device *ndev, void *mgbe_
143145
return err;
144146
}
145147

148+
usleep_range(10, 20); /* 50ns min delay needed as per HW design */
146149
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
147150
value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_DATA_EN;
148151
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
149152

150153
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
151-
value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET;
154+
value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_PCS_PHY_RDY;
152155
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
153156

157+
usleep_range(10, 20); /* 50ns min delay needed as per HW design */
154158
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
155-
value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET;
159+
value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET;
156160
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
157161

162+
usleep_range(10, 20); /* 50ns min delay needed as per HW design */
158163
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
159164
value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_PCS_PHY_RDY;
160165
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
161166

167+
msleep(30); /* 30ms delay needed as per HW design */
168+
value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
169+
value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET;
170+
writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
171+
162172
err = readl_poll_timeout(mgbe->xpcs + XPCS_WRAP_IRQ_STATUS, value,
163173
value & XPCS_WRAP_IRQ_STATUS_PCS_LINK_STS,
164174
500, 500 * 2000);

0 commit comments

Comments
 (0)