[PATCH v2 1/2] net: xilinx_axi: add PCS/PMA PHY

Andy Chiu andy.chiu at sifive.com
Tue Nov 1 04:57:59 CET 2022


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 at sifive.com>
Reviewed-by: Greentime Hu <greentime.hu at 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;
-- 
2.36.0



More information about the U-Boot mailing list