[PATCH v2 0/2] Manage PCS/PMA PHY if pressent

If both PCS/PMA PHY and an external PHY are pressent on the Ethernet, then the real link status should point to the external facing PHY. At the same time, we must ensure the link status of the PCS/PMA PHY is good before transmitting packets.
Change Log: --- v2 --- 1. Fix typo: use pcs-handle instead of pcs-phy in DT 2. Move printing of status waiting of pcs phy to debug and refactor code.
Andy Chiu (2): net: xilinx_axi: add PCS/PMA PHY net: xilinx_axi: check PCS/PMA PHY status in setup_phy
drivers/net/xilinx_axi_emac.c | 70 ++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-)

If we bridge an external PHY to Xilinx's PCS/PMA PHY and would like to get and set the real status of the PHY facing the external world. Then we should phy_connect() to the external PHY instead of the PCS/PMA one. Thus, we add a pcs-handle DT entry, which have been merged in Linux, and leave the configuration of it to the driver itself.
Unlike Linux, where the PCS/PMA PHY is managed by phylink, managing the PCS/PMA PHY is only internal to the driver in U-Boot. The PCS/PMA PHY pressents only when the phy-mode is configured as SGMII or 1000Base-X, so it is always 1 Gbps and full-duplex and we may skip passing link information out.
Signed-off-by: Andy Chiu andy.chiu@sifive.com Reviewed-by: Greentime Hu greentime.hu@sifive.com --- drivers/net/xilinx_axi_emac.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 04277b1269..cb5487c437 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -107,6 +107,7 @@ struct axidma_plat { struct eth_pdata eth_pdata; struct axidma_reg *dmatx; struct axidma_reg *dmarx; + int pcsaddr; int phyaddr; u8 eth_hasnobuf; int phy_of_handle; @@ -117,6 +118,7 @@ struct axidma_plat { struct axidma_priv { struct axidma_reg *dmatx; struct axidma_reg *dmarx; + int pcsaddr; int phyaddr; struct axi_regs *iobase; phy_interface_t interface; @@ -299,6 +301,13 @@ static int axiemac_phy_init(struct udevice *dev) if (IS_ENABLED(CONFIG_DM_ETH_PHY)) priv->phyaddr = eth_phy_get_addr(dev);
+ /* + * Set address of PCS/PMA PHY to the one pointed by phy-handle for + * backward compatibility. + */ + if (priv->phyaddr != -1 && priv->pcsaddr == 0) + priv->pcsaddr = priv->phyaddr; + if (priv->phyaddr == -1) { /* Detect the PHY address */ for (i = 31; i >= 0; i--) { @@ -342,12 +351,12 @@ static int setup_phy(struct udevice *dev) * after DMA and ethernet resets and hence * check and clear if set. */ - ret = phyread(priv, priv->phyaddr, MII_BMCR, &temp); + ret = phyread(priv, priv->pcsaddr, MII_BMCR, &temp); if (ret) return 0; if (temp & BMCR_ISOLATE) { temp &= ~BMCR_ISOLATE; - ret = phywrite(priv, priv->phyaddr, MII_BMCR, temp); + ret = phywrite(priv, priv->pcsaddr, MII_BMCR, temp); if (ret) return 0; } @@ -778,6 +787,7 @@ static int axi_emac_probe(struct udevice *dev)
if (priv->mactype == EMAC_1G) { priv->eth_hasnobuf = plat->eth_hasnobuf; + priv->pcsaddr = plat->pcsaddr; priv->phyaddr = plat->phyaddr; priv->phy_of_handle = plat->phy_of_handle; priv->interface = pdata->phy_interface; @@ -855,6 +865,8 @@ static int axi_emac_of_to_plat(struct udevice *dev)
if (plat->mactype == EMAC_1G) { plat->phyaddr = -1; + /* PHYAD 0 always redirects to the PCS/PMA PHY */ + plat->pcsaddr = 0;
offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy-handle"); @@ -872,6 +884,16 @@ static int axi_emac_of_to_plat(struct udevice *dev)
plat->eth_hasnobuf = fdtdec_get_bool(gd->fdt_blob, node, "xlnx,eth-hasnobuf"); + + if (pdata->phy_interface == PHY_INTERFACE_MODE_SGMII || + pdata->phy_interface == PHY_INTERFACE_MODE_1000BASEX) { + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, + "pcs-handle"); + if (offset > 0) { + plat->pcsaddr = fdtdec_get_int(gd->fdt_blob, + offset, "reg", -1); + } + } }
return 0;

Both PCS/PMA PHY and the external PHY need to have a valid link status in order to have Ethernet traffic. Check and wait this status at setup_phy() so that we could diagnose if there is a PHY issue.
Signed-off-by: Andy Chiu andy.chiu@sifive.com Reviewed-by: Greentime Hu greentime.hu@sifive.com --- drivers/net/xilinx_axi_emac.c | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index cb5487c437..10204db79b 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -336,6 +336,45 @@ static int axiemac_phy_init(struct udevice *dev) return 0; }
+static int pcs_pma_startup(struct axidma_priv *priv) +{ + u32 rc, retry_cnt = 0; + u16 mii_reg; + + rc = phyread(priv, priv->pcsaddr, MII_BMCR, &mii_reg); + if (rc) + goto failed_mdio; + + if (!(mii_reg & BMCR_ANENABLE)) { + mii_reg |= BMCR_ANENABLE; + if (phywrite(priv, priv->pcsaddr, MII_BMCR, mii_reg)) + goto failed_mdio; + } + + /* + * Check the internal PHY status and warn user if the link between it + * and the external PHY is not obtained. + */ + debug("axiemac: waiting for link status of the PCS/PMA PHY"); + while (retry_cnt * 10 < PHY_ANEG_TIMEOUT) { + rc = phyread(priv, priv->pcsaddr, MII_BMSR, &mii_reg); + if ((mii_reg & BMSR_LSTATUS) && mii_reg != 0xffff && !rc) { + debug(".Done\n"); + return 0; + } + if ((retry_cnt++ % 10) == 0) + debug("."); + mdelay(10); + } + debug("\n"); + printf("axiemac: Warning, PCS/PMA PHY@%d is not ready, link is down\n", + priv->pcsaddr); + return 1; +failed_mdio: + printf("axiemac: MDIO to the PCS/PMA PHY has failed\n"); + return 1; +} + /* Setting axi emac and phy to proper setting */ static int setup_phy(struct udevice *dev) { @@ -367,6 +406,11 @@ static int setup_phy(struct udevice *dev) phydev->dev->name); return 0; } + if (priv->interface == PHY_INTERFACE_MODE_SGMII || + priv->interface == PHY_INTERFACE_MODE_1000BASEX) { + if (pcs_pma_startup(priv)) + return 0; + } if (!phydev->link) { printf("%s: No link.\n", phydev->dev->name); return 0;

On 11/1/22 04:57, Andy Chiu wrote:
If both PCS/PMA PHY and an external PHY are pressent on the Ethernet, then the real link status should point to the external facing PHY. At the same time, we must ensure the link status of the PCS/PMA PHY is good before transmitting packets.
Change Log: --- v2 ---
- Fix typo: use pcs-handle instead of pcs-phy in DT
- Move printing of status waiting of pcs phy to debug and refactor code.
Andy Chiu (2): net: xilinx_axi: add PCS/PMA PHY net: xilinx_axi: check PCS/PMA PHY status in setup_phy
drivers/net/xilinx_axi_emac.c | 70 ++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-)
Applied. M
participants (2)
-
Andy Chiu
-
Michal Simek