return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
 }
 
-static int xpcs_dev_flag(struct dw_xpcs *xpcs)
-{
-       int ret, oui;
-
-       ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
-       if (ret < 0)
-               return ret;
-
-       oui = ret;
-
-       ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
-       if (ret < 0)
-               return ret;
-
-       ret = (ret >> 10) & 0x3F;
-       oui |= ret << 16;
-
-       if (oui == DW_OUI_WX)
-               xpcs->dev_flag = DW_DEV_TXGBE;
-
-       return 0;
-}
-
 static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
 {
        /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
 {
        int ret, mdio_ctrl, tx_conf;
 
-       if (xpcs->dev_flag == DW_DEV_TXGBE)
+       if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID)
                xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
 
        /* For AN for C37 SGMII mode, the settings are :-
        ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
                DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
                DW_VR_MII_PCS_MODE_MASK);
-       if (xpcs->dev_flag == DW_DEV_TXGBE) {
+       if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
                ret |= DW_VR_MII_AN_CTRL_8BIT;
                /* Hardware requires it to be PHY side SGMII */
                tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
        else
                ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
 
-       if (xpcs->dev_flag == DW_DEV_TXGBE)
+       if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID)
                ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
 
        ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
        int ret, mdio_ctrl, adv;
        bool changed = 0;
 
-       if (xpcs->dev_flag == DW_DEV_TXGBE)
+       if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID)
                xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
 
        /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
        if (!compat)
                return -ENODEV;
 
-       if (xpcs->dev_flag == DW_DEV_TXGBE) {
+       if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
                ret = txgbe_xpcs_switch_mode(xpcs, interface);
                if (ret)
                        return ret;
        }
 }
 
-static u32 xpcs_get_id(struct dw_xpcs *xpcs)
+static int xpcs_get_id(struct dw_xpcs *xpcs)
 {
        int ret;
        u32 id;
 
-       /* First, search C73 PCS using PCS MMD */
+       /* First, search C73 PCS using PCS MMD 3. Return ENODEV if communication
+        * failed indicating that device couldn't be reached.
+        */
        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
        if (ret < 0)
-               return 0xffffffff;
+               return -ENODEV;
 
        id = ret << 16;
 
        ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
        if (ret < 0)
-               return 0xffffffff;
+               return ret;
 
-       /* If Device IDs are not all zeros or all ones,
-        * we found C73 AN-type device
+       id |= ret;
+
+       /* If Device IDs are not all zeros or ones, then 10GBase-X/R or C73
+        * KR/KX4 PCS found. Otherwise fallback to detecting 1000Base-X or C37
+        * PCS in MII MMD 31.
         */
-       if ((id | ret) && (id | ret) != 0xffffffff)
-               return id | ret;
+       if (!id || id == 0xffffffff) {
+               ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
+               if (ret < 0)
+                       return ret;
+
+               id = ret << 16;
+
+               ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
+               if (ret < 0)
+                       return ret;
 
-       /* Next, search C37 PCS using Vendor-Specific MII MMD */
-       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
+               id |= ret;
+       }
+
+       xpcs->info.pcs = id;
+
+       /* Find out PMA/PMD ID from MMD 1 device ID registers */
+       ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
        if (ret < 0)
-               return 0xffffffff;
+               return ret;
 
-       id = ret << 16;
+       id = ret;
 
-       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
+       ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
        if (ret < 0)
-               return 0xffffffff;
+               return ret;
+
+       /* Note the inverted dword order and masked out Model/Revision numbers
+        * with respect to what is done with the PCS ID...
+        */
+       ret = (ret >> 10) & 0x3F;
+       id |= ret << 16;
 
-       /* If Device IDs are not all zeros, we found C37 AN-type device */
-       if (id | ret)
-               return id | ret;
+       xpcs->info.pma = id;
 
-       return 0xffffffff;
+       return 0;
 }
 
 static const struct dw_xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
 
 static int xpcs_init_id(struct dw_xpcs *xpcs)
 {
-       u32 xpcs_id;
        int i, ret;
 
-       xpcs_id = xpcs_get_id(xpcs);
+       ret = xpcs_get_id(xpcs);
+       if (ret < 0)
+               return ret;
 
        for (i = 0; i < ARRAY_SIZE(xpcs_desc_list); i++) {
                const struct dw_xpcs_desc *desc = &xpcs_desc_list[i];
 
-               if ((xpcs_id & desc->mask) != desc->id)
+               if ((xpcs->info.pcs & desc->mask) != desc->id)
                        continue;
 
                xpcs->desc = desc;
        if (!xpcs->desc)
                return -ENODEV;
 
-       ret = xpcs_dev_flag(xpcs);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
        if (!compat)
                return -EINVAL;
 
-       if (xpcs->dev_flag == DW_DEV_TXGBE) {
+       if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
                xpcs->pcs.poll = false;
                return 0;
        }
 
 
 #include <linux/phy.h>
 #include <linux/phylink.h>
-
-#define NXP_SJA1105_XPCS_ID            0x00000010
-#define NXP_SJA1110_XPCS_ID            0x00000020
-#define DW_XPCS_ID                     0x7996ced0
-#define DW_XPCS_ID_MASK                        0xffffffff
+#include <linux/types.h>
 
 /* AN mode */
 #define DW_AN_C73                      1
 #define DW_AN_C37_1000BASEX            4
 #define DW_10GBASER                    5
 
-/* device vendor OUI */
-#define DW_OUI_WX                      0x0018fc80
+struct dw_xpcs_desc;
 
-/* dev_flag */
-#define DW_DEV_TXGBE                   BIT(0)
+enum dw_xpcs_pcs_id {
+       NXP_SJA1105_XPCS_ID = 0x00000010,
+       NXP_SJA1110_XPCS_ID = 0x00000020,
+       DW_XPCS_ID = 0x7996ced0,
+       DW_XPCS_ID_MASK = 0xffffffff,
+};
 
-struct dw_xpcs_desc;
+enum dw_xpcs_pma_id {
+       WX_TXGBE_XPCS_PMA_10G_ID = 0x0018fc80,
+};
+
+struct dw_xpcs_info {
+       u32 pcs;
+       u32 pma;
+};
 
 struct dw_xpcs {
+       struct dw_xpcs_info info;
        const struct dw_xpcs_desc *desc;
        struct mdio_device *mdiodev;
        struct phylink_pcs pcs;
        phy_interface_t interface;
-       int dev_flag;
 };
 
 int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);