#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX     7
 #define MEDIA_OP_MODE_POS                8
 
+#define MSCC_PHY_EXT_PHY_CNTL_2                  24
+
 #define MII_VSC85XX_INT_MASK             25
 #define MII_VSC85XX_INT_MASK_MASK        0xa000
 #define MII_VSC85XX_INT_MASK_WOL         0x0040
 #define DW8051_CLK_EN                    0x0010
 #define MICRO_CLK_EN                     0x0008
 #define MICRO_CLK_DIVIDE(x)              ((x) >> 1)
+#define MSCC_DW8051_VLD_MASK             0xf1ff
 
 /* x Address in range 1-4 */
 #define MSCC_TRAP_ROM_ADDR(x)            ((x) * 2 + 1)
 #define PROC_CMD_SGMII_MAC               0x0030
 #define PROC_CMD_QSGMII_MAC              0x0020
 #define PROC_CMD_NO_MAC_CONF             0x0000
+#define PROC_CMD_1588_DEFAULT_INIT       0x0010
 #define PROC_CMD_NOP                     0x000f
+#define PROC_CMD_PHY_INIT                0x000a
 #define PROC_CMD_CRC16                   0x0008
 #define PROC_CMD_FIBER_MEDIA_CONF        0x0001
 #define PROC_CMD_MCB_ACCESS_MAC_CONF     0x0000
 /* Test page Registers */
 #define MSCC_PHY_TEST_PAGE_5             5
 #define MSCC_PHY_TEST_PAGE_8             8
+#define MSCC_PHY_TEST_PAGE_9             9
+#define MSCC_PHY_TEST_PAGE_20            20
+#define MSCC_PHY_TEST_PAGE_24            24
 
 /* Token ring page Registers */
 #define MSCC_PHY_TR_CNTL                 16
 #define PHY_ID_VSC8531                   0x00070570
 #define PHY_ID_VSC8540                   0x00070760
 #define PHY_ID_VSC8541                   0x00070770
+#define PHY_ID_VSC8574                   0x000704a0
 #define PHY_ID_VSC8584                   0x000707c0
 
 #define MSCC_VDDMAC_1500                 1500
 #define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR        0xe800
 #define MSCC_VSC8584_REVB_INT8051_FW_CRC       0xfb48
 
+#define MSCC_VSC8574_REVB_INT8051_FW           "mscc_vsc8574_revb_int8051_29e8.bin"
+#define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR        0x4000
+#define MSCC_VSC8574_REVB_INT8051_FW_CRC       0x29e8
+
 #define VSC8584_REVB                           0x0001
 #define MSCC_DEV_REV_MASK                      GENMASK(3, 0)
 
        return 0;
 }
 
+/* bus->mdio_lock should be locked when using this function */
+static bool vsc8574_is_serdes_init(struct phy_device *phydev)
+{
+       u16 reg;
+       bool ret;
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+                      MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+       reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));
+       if (reg != 0x3eb7) {
+               ret = false;
+               goto out;
+       }
+
+       reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));
+       if (reg != 0x4012) {
+               ret = false;
+               goto out;
+       }
+
+       reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
+       if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
+               ret = false;
+               goto out;
+       }
+
+       reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
+       if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM |  DW8051_CLK_EN |
+            MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
+               ret = false;
+               goto out;
+       }
+
+       ret = true;
+out:
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+       return ret;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8574_config_pre_init(struct phy_device *phydev)
+{
+       const struct reg_val pre_init1[] = {
+               {0x0fae, 0x000401bd},
+               {0x0fac, 0x000f000f},
+               {0x17a0, 0x00a0f147},
+               {0x0fe4, 0x00052f54},
+               {0x1792, 0x0027303d},
+               {0x07fe, 0x00000704},
+               {0x0fe0, 0x00060150},
+               {0x0f82, 0x0012b00a},
+               {0x0f80, 0x00000d74},
+               {0x02e0, 0x00000012},
+               {0x03a2, 0x00050208},
+               {0x03b2, 0x00009186},
+               {0x0fb0, 0x000e3700},
+               {0x1688, 0x00049f81},
+               {0x0fd2, 0x0000ffff},
+               {0x168a, 0x00039fa2},
+               {0x1690, 0x0020640b},
+               {0x0258, 0x00002220},
+               {0x025a, 0x00002a20},
+               {0x025c, 0x00003060},
+               {0x025e, 0x00003fa0},
+               {0x03a6, 0x0000e0f0},
+               {0x0f92, 0x00001489},
+               {0x16a2, 0x00007000},
+               {0x16a6, 0x00071448},
+               {0x16a0, 0x00eeffdd},
+               {0x0fe8, 0x0091b06c},
+               {0x0fea, 0x00041600},
+               {0x16b0, 0x00eeff00},
+               {0x16b2, 0x00007000},
+               {0x16b4, 0x00000814},
+               {0x0f90, 0x00688980},
+               {0x03a4, 0x0000d8f0},
+               {0x0fc0, 0x00000400},
+               {0x07fa, 0x0050100f},
+               {0x0796, 0x00000003},
+               {0x07f8, 0x00c3ff98},
+               {0x0fa4, 0x0018292a},
+               {0x168c, 0x00d2c46f},
+               {0x17a2, 0x00000620},
+               {0x16a4, 0x0013132f},
+               {0x16a8, 0x00000000},
+               {0x0ffc, 0x00c0a028},
+               {0x0fec, 0x00901c09},
+               {0x0fee, 0x0004a6a1},
+               {0x0ffe, 0x00b01807},
+       };
+       const struct reg_val pre_init2[] = {
+               {0x0486, 0x0008a518},
+               {0x0488, 0x006dc696},
+               {0x048a, 0x00000912},
+               {0x048e, 0x00000db6},
+               {0x049c, 0x00596596},
+               {0x049e, 0x00000514},
+               {0x04a2, 0x00410280},
+               {0x04a4, 0x00000000},
+               {0x04a6, 0x00000000},
+               {0x04a8, 0x00000000},
+               {0x04aa, 0x00000000},
+               {0x04ae, 0x007df7dd},
+               {0x04b0, 0x006d95d4},
+               {0x04b2, 0x00492410},
+       };
+       struct device *dev = &phydev->mdio.dev;
+       const struct firmware *fw;
+       unsigned int i;
+       u16 crc, reg;
+       bool serdes_init;
+       int ret;
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+       /* all writes below are broadcasted to all PHYs in the same package */
+       reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
+       reg |= SMI_BROADCAST_WR_EN;
+       phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+       phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
+
+       /* The below register writes are tweaking analog and electrical
+        * configuration that were determined through characterization by PHY
+        * engineers. These don't mean anything more than "these are the best
+        * values".
+        */
+       phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
+
+       phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);
+       phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);
+       phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);
+       phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);
+
+       reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
+       reg |= 0x8000;
+       phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+       for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
+               vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
+
+       phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+       for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
+               vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
+
+       reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
+       reg &= ~0x8000;
+       phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+       /* end of write broadcasting */
+       reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
+       reg &= ~SMI_BROADCAST_WR_EN;
+       phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+       ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);
+       if (ret) {
+               dev_err(dev, "failed to load firmware %s, ret: %d\n",
+                       MSCC_VSC8574_REVB_INT8051_FW, ret);
+               return ret;
+       }
+
+       /* Add one byte to size for the one added by the patch_fw function */
+       ret = vsc8584_get_fw_crc(phydev,
+                                MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
+                                fw->size + 1, &crc);
+       if (ret)
+               goto out;
+
+       if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
+               serdes_init = vsc8574_is_serdes_init(phydev);
+
+               if (!serdes_init) {
+                       ret = vsc8584_micro_assert_reset(phydev);
+                       if (ret) {
+                               dev_err(dev,
+                                       "%s: failed to assert reset of micro\n",
+                                       __func__);
+                               return ret;
+                       }
+               }
+       } else {
+               dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
+
+               serdes_init = false;
+
+               if (vsc8584_patch_fw(phydev, fw))
+                       dev_warn(dev,
+                                "failed to patch FW, expect non-optimal device\n");
+       }
+
+       if (!serdes_init) {
+               phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+                              MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+               phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);
+               phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);
+               phy_base_write(phydev, MSCC_INT_MEM_CNTL,
+                              EN_PATCH_RAM_TRAP_ADDR(1));
+
+               vsc8584_micro_deassert_reset(phydev, false);
+
+               /* Add one byte to size for the one added by the patch_fw
+                * function
+                */
+               ret = vsc8584_get_fw_crc(phydev,
+                                        MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
+                                        fw->size + 1, &crc);
+               if (ret)
+                       goto out;
+
+               if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
+                       dev_warn(dev,
+                                "FW CRC after patching is not the expected one, expect non-optimal device\n");
+       }
+
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+                      MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+       ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |
+                         PROC_CMD_PHY_INIT);
+
+out:
+       phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+       release_firmware(fw);
+
+       return ret;
+}
+
 /* bus->mdio_lock should be locked when using this function */
 static int vsc8584_config_pre_init(struct phy_device *phydev)
 {
         * in this pre-init function.
         */
        if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
-               ret = vsc8584_config_pre_init(phydev);
+               if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
+                   (PHY_ID_VSC8574 & phydev->drv->phy_id_mask))
+                       ret = vsc8574_config_pre_init(phydev);
+               else if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
+                        (PHY_ID_VSC8584 & phydev->drv->phy_id_mask))
+                       ret = vsc8584_config_pre_init(phydev);
+               else
+                       ret = -EINVAL;
+
                if (ret)
                        goto err;
        }
        return genphy_read_status(phydev);
 }
 
+static int vsc8574_probe(struct phy_device *phydev)
+{
+       struct vsc8531_private *vsc8531;
+       u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
+          VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
+          VSC8531_DUPLEX_COLLISION};
+
+       vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
+       if (!vsc8531)
+               return -ENOMEM;
+
+       phydev->priv = vsc8531;
+
+       vsc8531->nleds = 4;
+       vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
+       vsc8531->hw_stats = vsc8584_hw_stats;
+       vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
+       vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
+                                           sizeof(u64), GFP_KERNEL);
+       if (!vsc8531->stats)
+               return -ENOMEM;
+
+       return vsc85xx_dt_led_modes_get(phydev, default_mode);
+}
+
 static int vsc8584_probe(struct phy_device *phydev)
 {
        struct vsc8531_private *vsc8531;
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
 },
+{
+       .phy_id         = PHY_ID_VSC8574,
+       .name           = "Microsemi GE VSC8574 SyncE",
+       .phy_id_mask    = 0xfffffff0,
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .soft_reset     = &genphy_soft_reset,
+       .config_init    = &vsc8584_config_init,
+       .config_aneg    = &vsc85xx_config_aneg,
+       .aneg_done      = &genphy_aneg_done,
+       .read_status    = &vsc85xx_read_status,
+       .ack_interrupt  = &vsc85xx_ack_interrupt,
+       .config_intr    = &vsc85xx_config_intr,
+       .did_interrupt  = &vsc8584_did_interrupt,
+       .suspend        = &genphy_suspend,
+       .resume         = &genphy_resume,
+       .probe          = &vsc8574_probe,
+       .set_wol        = &vsc85xx_wol_set,
+       .get_wol        = &vsc85xx_wol_get,
+       .get_tunable    = &vsc85xx_get_tunable,
+       .set_tunable    = &vsc85xx_set_tunable,
+       .read_page      = &vsc85xx_phy_read_page,
+       .write_page     = &vsc85xx_phy_write_page,
+       .get_sset_count = &vsc85xx_get_sset_count,
+       .get_strings    = &vsc85xx_get_strings,
+       .get_stats      = &vsc85xx_get_stats,
+},
 {
        .phy_id         = PHY_ID_VSC8584,
        .name           = "Microsemi GE VSC8584 SyncE",
        { PHY_ID_VSC8531, 0xfffffff0, },
        { PHY_ID_VSC8540, 0xfffffff0, },
        { PHY_ID_VSC8541, 0xfffffff0, },
+       { PHY_ID_VSC8574, 0xfffffff0, },
        { PHY_ID_VSC8584, 0xfffffff0, },
        { }
 };