aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2023-01-25 08:09:08 +0100
committerMichal Simek <michal.simek@amd.com>2023-01-27 08:47:37 +0100
commita33ad8051e0fdcc2af34259006c470899ad8cd77 (patch)
treeee0cd91187aba953b6375d5d819d9149bf4fe554
parentb387c258240c761f61fbcd0c9b33039275219002 (diff)
downloadu-boot-a33ad8051e0fdcc2af34259006c470899ad8cd77.zip
u-boot-a33ad8051e0fdcc2af34259006c470899ad8cd77.tar.gz
u-boot-a33ad8051e0fdcc2af34259006c470899ad8cd77.tar.bz2
net: zynq_gem: Wait for SGMII PCS link in zynq_gem_init()
In our system using ZynqMP with an external SGMII PHY it's necessary to wait for the PCS link and auto negotiation to finish before the xfer starts. Otherwise the first packet(s) might get dropped, resulting in a delay at the start of the ethernet transfers. This is only done when the PHY link is already up, which is done in phy_startup(). As waiting for the PHY link bits via pcsstatus does not make much sense, when the link is not available in general (e.g. no cable connected). This patch adds the necessary code including a minimal delay of 1 ms which fixes problems of dropped first packages. Signed-off-by: Stefan Roese <sr@denx.de> Cc: Michal Simek <michal.simek@amd.com> Cc: Katakam Harini <harini.katakam@amd.com> Cc: Ramon Fried <rfried.dev@gmail.com> Cc: Sean Anderson <sean.anderson@seco.com> Link: https://lore.kernel.org/r/20230125070908.1343256-1-sr@denx.de Signed-off-by: Michal Simek <michal.simek@amd.com>
-rw-r--r--drivers/net/zynq_gem.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index fe98bcf..cc49788 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -125,6 +125,10 @@
*/
#define PHY_DETECT_MASK 0x1808
+/* PCS (SGMII) Link Status */
+#define ZYNQ_GEM_PCSSTATUS_LINK BIT(2)
+#define ZYNQ_GEM_PCSSTATUS_ANEG_COMPL BIT(5)
+
/* TX BD status masks */
#define ZYNQ_GEM_TXBUF_FRMLEN_MASK 0x000007ff
#define ZYNQ_GEM_TXBUF_EXHAUSTED 0x08000000
@@ -164,7 +168,8 @@ struct zynq_gem_regs {
u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */
u32 reserved9[20];
u32 pcscntrl;
- u32 rserved12[36];
+ u32 pcsstatus;
+ u32 rserved12[35];
u32 dcfg6; /* 0x294 Design config reg6 */
u32 reserved7[106];
u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */
@@ -491,12 +496,37 @@ static int zynq_gem_init(struct udevice *dev)
* Must be written after PCS_SEL is set in nwconfig,
* otherwise writes will not take effect.
*/
- if (priv->phydev->phy_id != PHY_FIXED_ID)
+ if (priv->phydev->phy_id != PHY_FIXED_ID) {
writel(readl(&regs->pcscntrl) | ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
&regs->pcscntrl);
- else
+ /*
+ * When the PHY link is already up, the PCS link needs
+ * to get re-checked
+ */
+ if (priv->phydev->link) {
+ u32 pcsstatus;
+
+ pcsstatus = ZYNQ_GEM_PCSSTATUS_LINK |
+ ZYNQ_GEM_PCSSTATUS_ANEG_COMPL;
+ ret = wait_for_bit_le32(&regs->pcsstatus,
+ pcsstatus,
+ true, 5000, true);
+ if (ret) {
+ dev_warn(dev,
+ "no PCS (SGMII) link\n");
+ } else {
+ /*
+ * Some additional minimal delay seems
+ * to be needed so that the first
+ * packet will be sent correctly
+ */
+ mdelay(1);
+ }
+ }
+ } else {
writel(readl(&regs->pcscntrl) & ~ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
&regs->pcscntrl);
+ }
}
#endif