#include <linux/acpi.h>
 #include <linux/pcs-lynx.h>
+#include <linux/phy/phy.h>
 #include <linux/property.h>
 
 #include "dpaa2-eth.h"
        return 0;
 }
 
+static enum dpmac_eth_if dpmac_eth_if_mode(phy_interface_t if_mode)
+{
+       switch (if_mode) {
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               return DPMAC_ETH_IF_RGMII;
+       case PHY_INTERFACE_MODE_USXGMII:
+               return DPMAC_ETH_IF_USXGMII;
+       case PHY_INTERFACE_MODE_QSGMII:
+               return DPMAC_ETH_IF_QSGMII;
+       case PHY_INTERFACE_MODE_SGMII:
+               return DPMAC_ETH_IF_SGMII;
+       case PHY_INTERFACE_MODE_10GBASER:
+               return DPMAC_ETH_IF_XFI;
+       case PHY_INTERFACE_MODE_1000BASEX:
+               return DPMAC_ETH_IF_1000BASEX;
+       default:
+               return DPMAC_ETH_IF_MII;
+       }
+}
+
 static struct fwnode_handle *dpaa2_mac_get_node(struct device *dev,
                                                u16 dpmac_id)
 {
        if (err)
                netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n",
                           __func__, err);
+
+       if (!mac->serdes_phy)
+               return;
+
+       /* This happens only if we support changing of protocol at runtime */
+       err = dpmac_set_protocol(mac->mc_io, 0, mac->mc_dev->mc_handle,
+                                dpmac_eth_if_mode(state->interface));
+       if (err)
+               netdev_err(mac->net_dev,  "dpmac_set_protocol() = %d\n", err);
+
+       err = phy_set_mode_ext(mac->serdes_phy, PHY_MODE_ETHERNET, state->interface);
+       if (err)
+               netdev_err(mac->net_dev, "phy_set_mode_ext() = %d\n", err);
 }
 
 static void dpaa2_mac_link_up(struct phylink_config *config,
 
 static void dpaa2_mac_set_supported_interfaces(struct dpaa2_mac *mac)
 {
+       int intf, err;
+
        /* We support the current interface mode, and if we have a PCS
         * similar interface modes that do not require the SerDes lane to be
         * reconfigured.
                        break;
                }
        }
+
+       if (!mac->serdes_phy)
+               return;
+
+       /* In case we have access to the SerDes phy/lane, then ask the SerDes
+        * driver what interfaces are supported based on the current PLL
+        * configuration.
+        */
+       for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
+               if (intf == PHY_INTERFACE_MODE_NA)
+                       continue;
+
+               err = phy_validate(mac->serdes_phy, PHY_MODE_ETHERNET, intf, NULL);
+               if (err)
+                       continue;
+
+               __set_bit(intf, mac->phylink_config.supported_interfaces);
+       }
+}
+
+void dpaa2_mac_start(struct dpaa2_mac *mac)
+{
+       if (mac->serdes_phy)
+               phy_power_on(mac->serdes_phy);
+}
+
+void dpaa2_mac_stop(struct dpaa2_mac *mac)
+{
+       if (mac->serdes_phy)
+               phy_power_off(mac->serdes_phy);
 }
 
 int dpaa2_mac_connect(struct dpaa2_mac *mac)
 {
        struct net_device *net_dev = mac->net_dev;
        struct fwnode_handle *dpmac_node;
+       struct phy *serdes_phy = NULL;
        struct phylink *phylink;
        int err;
 
                return -EINVAL;
        mac->if_mode = err;
 
+       if (mac->features & DPAA2_MAC_FEATURE_PROTOCOL_CHANGE &&
+           !phy_interface_mode_is_rgmii(mac->if_mode) &&
+           is_of_node(dpmac_node)) {
+               serdes_phy = of_phy_get(to_of_node(dpmac_node), NULL);
+
+               if (serdes_phy == ERR_PTR(-ENODEV))
+                       serdes_phy = NULL;
+               else if (IS_ERR(serdes_phy))
+                       return PTR_ERR(serdes_phy);
+               else
+                       phy_init(serdes_phy);
+       }
+       mac->serdes_phy = serdes_phy;
+
        /* The MAC does not have the capability to add RGMII delays so
         * error out if the interface mode requests them and there is no PHY
         * to act upon them
        phylink_disconnect_phy(mac->phylink);
        phylink_destroy(mac->phylink);
        dpaa2_pcs_destroy(mac);
+       of_phy_put(mac->serdes_phy);
+       mac->serdes_phy = NULL;
 }
 
 int dpaa2_mac_open(struct dpaa2_mac *mac)