diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index f14b484b26..da533a1e5d 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -39,6 +39,152 @@ static int enetc_bind(struct udevice *dev)
 	return 0;
 }
 
+/* MDIO wrappers, we're using these to drive internal MDIO to get to serdes */
+static int enetc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct enetc_mdio_priv priv;
+
+	priv.regs_base = bus->priv;
+	return enetc_mdio_read_priv(&priv, addr, devad, reg);
+}
+
+static int enetc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			    u16 val)
+{
+	struct enetc_mdio_priv priv;
+
+	priv.regs_base = bus->priv;
+	return enetc_mdio_write_priv(&priv, addr, devad, reg, val);
+}
+
+/* only interfaces that can pin out through serdes have internal MDIO */
+static bool enetc_has_imdio(struct udevice *dev)
+{
+	struct enetc_priv *priv = dev_get_priv(dev);
+
+	return !!(priv->imdio.priv);
+}
+
+/* set up serdes for SGMII */
+static int enetc_init_sgmii(struct udevice *dev)
+{
+	struct enetc_priv *priv = dev_get_priv(dev);
+
+	if (!enetc_has_imdio(dev))
+		return 0;
+
+	/* Set to SGMII mode, use AN */
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+			 ENETC_PCS_IF_MODE, ENETC_PCS_IF_MODE_SGMII_AN);
+
+	/* Dev ability - SGMII */
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+			 ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SGMII);
+
+	/* Adjust link timer for SGMII */
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+			 ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+			 ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
+
+	/* restart PCS AN */
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+			 ENETC_PCS_CR,
+			 ENETC_PCS_CR_RESET_AN | ENETC_PCS_CR_DEF_VAL);
+
+	return 0;
+}
+
+/* set up MAC for RGMII */
+static int enetc_init_rgmii(struct udevice *dev)
+{
+	struct enetc_priv *priv = dev_get_priv(dev);
+	u32 if_mode;
+
+	/* enable RGMII AN */
+	if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
+	if_mode |= ENETC_PM_IF_MODE_AN_ENA;
+	enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+
+	return 0;
+}
+
+/* set up MAC and serdes for SXGMII */
+static int enetc_init_sxgmii(struct udevice *dev)
+{
+	struct enetc_priv *priv = dev_get_priv(dev);
+	u32 if_mode;
+
+	/* set ifmode to (US)XGMII */
+	if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
+	if_mode &= ~ENETC_PM_IF_IFMODE_MASK;
+	enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+
+	if (!enetc_has_imdio(dev))
+		return 0;
+
+	/* Dev ability - SXGMII */
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL,
+			 ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
+
+	/* Restart PCS AN */
+	enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL,
+			 ENETC_PCS_CR,
+			 ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN);
+
+	return 0;
+}
+
+/* Apply protocol specific configuration to MAC, serdes as needed */
+static void enetc_start_pcs(struct udevice *dev)
+{
+	struct enetc_priv *priv = dev_get_priv(dev);
+	const char *if_str;
+
+	priv->if_type = PHY_INTERFACE_MODE_NONE;
+
+	/* check internal mdio capability, not all ports need it */
+	if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) {
+		/*
+		 * set up internal MDIO, this is part of ETH PCI function and is
+		 * used to access serdes / internal SoC PHYs.
+		 * We don't currently register it as a MDIO bus as it goes away
+		 * when the interface is removed, so it can't practically be
+		 * used in the console.
+		 */
+		priv->imdio.read = enetc_mdio_read;
+		priv->imdio.write = enetc_mdio_write;
+		priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE;
+		strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN);
+	}
+
+	if (!ofnode_valid(dev->node)) {
+		enetc_dbg(dev, "no enetc ofnode found, skipping PCS set-up\n");
+		return;
+	}
+
+	if_str = ofnode_read_string(dev->node, "phy-mode");
+	if (if_str)
+		priv->if_type = phy_get_interface_by_name(if_str);
+	else
+		enetc_dbg(dev,
+			  "phy-mode property not found, defaulting to SGMII\n");
+	if (priv->if_type < 0)
+		priv->if_type = PHY_INTERFACE_MODE_NONE;
+
+	switch (priv->if_type) {
+	case PHY_INTERFACE_MODE_SGMII:
+		enetc_init_sgmii(dev);
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+		enetc_init_rgmii(dev);
+		break;
+	case PHY_INTERFACE_MODE_XGMII:
+		enetc_init_sxgmii(dev);
+		break;
+	};
+}
+
 /* Configure the actual/external ethernet PHY, if one is found */
 static void enetc_start_phy(struct udevice *dev)
 {
@@ -303,7 +449,7 @@ static int enetc_start(struct udevice *dev)
 	enetc_setup_tx_bdr(dev);
 	enetc_setup_rx_bdr(dev);
 
-	priv->if_type = PHY_INTERFACE_MODE_NONE;
+	enetc_start_pcs(dev);
 	enetc_start_phy(dev);
 
 	return 0;
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
index fbb9dfa15e..ac8d38da92 100644
--- a/drivers/net/fsl_enetc.h
+++ b/drivers/net/fsl_enetc.h
@@ -61,6 +61,8 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PSIPMMR			0x0018
 #define ENETC_PSIPMAR0			0x0100
 #define ENETC_PSIPMAR1			0x0104
+#define ENETC_PCAPR0			0x0900
+#define  ENETC_PCAPRO_MDIO		BIT(11)
 #define ENETC_PSICFGR(n)		(0x0940 + (n) * 0x10)
 #define  ENETC_PSICFGR_SET_TXBDR(val)	((val) & 0xff)
 #define  ENETC_PSICFGR_SET_RXBDR(val)	(((val) & 0xff) << 16)
@@ -70,6 +72,11 @@ enum enetc_bdr_type {TX, RX};
 #define  ENETC_PM_CC_RX_TX_EN		0x8813
 #define ENETC_PM_MAXFRM			0x8014
 #define  ENETC_RX_MAXFRM_SIZE		PKTSIZE_ALIGN
+#define ENETC_PM_IMDIO_BASE		0x8030
+#define ENETC_PM_IF_MODE		0x8300
+#define  ENETC_PM_IF_MODE_RG		BIT(2)
+#define  ENETC_PM_IF_MODE_AN_ENA	BIT(15)
+#define  ENETC_PM_IF_IFMODE_MASK	GENMASK(1, 0)
 
 /* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */
 #define ENETC_BD_CNT		CONFIG_SYS_RX_ETH_BUFFER
@@ -146,6 +153,7 @@ struct enetc_priv {
 	struct bd_ring rx_bdr;
 
 	int if_type;
+	struct mii_dev imdio;
 };
 
 /* register accessors */
@@ -168,6 +176,27 @@ struct enetc_priv {
 #define enetc_bdr_write(priv, t, n, off, val) \
 			enetc_write(priv, ENETC_BDR(t, n, off), val)
 
+/* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */
+#define ENETC_PCS_PHY_ADDR	0
+
+/* PCS registers */
+#define ENETC_PCS_CR			0x00
+#define ENETC_PCS_CR_RESET_AN		 0x1200
+#define ENETC_PCS_CR_DEF_VAL		 0x0140
+#define ENETC_PCS_CR_LANE_RESET		 0x8000
+#define ENETC_PCS_DEV_ABILITY		0x04
+#define ENETC_PCS_DEV_ABILITY_SGMII	 0x4001
+#define ENETC_PCS_DEV_ABILITY_SXGMII	 0x5001
+#define ENETC_PCS_LINK_TIMER1		0x12
+#define ENETC_PCS_LINK_TIMER1_VAL	 0x06a0
+#define ENETC_PCS_LINK_TIMER2		0x13
+#define ENETC_PCS_LINK_TIMER2_VAL	 0x0003
+#define ENETC_PCS_IF_MODE		0x14
+#define ENETC_PCS_IF_MODE_SGMII_AN	 0x0003
+
+/* PCS replicator block for USXGMII */
+#define ENETC_PCS_DEVAD_REPL		0x1f
+
 /* ENETC external MDIO registers */
 #define ENETC_MDIO_BASE		0x1c00
 #define ENETC_MDIO_CFG		0x00
@@ -186,4 +215,13 @@ struct enetc_mdio_priv {
 	void *regs_base;
 };
 
+/*
+ * these functions are implemented by ENETC_MDIO and are re-used by ENETC driver
+ * to drive serdes / internal SoC PHYs
+ */
+int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+			 int reg);
+int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+			  int reg, u16 val);
+
 #endif /* _ENETC_H */
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
index 46afac06d7..60d21537b8 100644
--- a/drivers/net/fsl_enetc_mdio.c
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -21,8 +21,8 @@ static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
 		cpu_relax();
 }
 
-static int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr,
-				int devad, int reg)
+int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+			 int reg)
 {
 	if (devad == MDIO_DEVAD_NONE)
 		enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
@@ -51,8 +51,8 @@ static int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr,
 	return enetc_read(priv, ENETC_MDIO_DATA);
 }
 
-static int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr,
-				 int devad, int reg, u16 val)
+int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+			  int reg, u16 val)
 {
 	if (devad == MDIO_DEVAD_NONE)
 		enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
