net: phy: mscc: add support for VSC8574 PHY
authorQuentin Schulz <quentin.schulz@bootlin.com>
Wed, 31 Oct 2018 10:20:39 +0000 (11:20 +0100)
committerJoe Hershberger <joe.hershberger@ni.com>
Mon, 5 Nov 2018 16:41:59 +0000 (10:41 -0600)
The VSC8574 PHY is a 4-port PHY that is 10/100/1000BASE-T, 100BASE-FX,
1000BASE-X and triple-speed copper SFP capable, can communicate with
the MAC via SGMII, QSGMII or 1000BASE-X, supports WOL, downshifting and
can set the blinking pattern of each of its 4 LEDs, supports SyncE as
well as HP Auto-MDIX detection.

This adds support for 10/100/1000BASE-T and SGMII/QSGMII link with the
MAC.

The VSC8574 has also an internal Intel 8051 microcontroller whose
firmware needs to be patched when the PHY is reset. If the 8051's
firmware has the expected CRC, its patching can be skipped. The
microcontroller can be accessed from any port of the PHY, though the CRC
function can only be done through the PHY that is the base PHY of the
package (internal address 0) due to a limitation of the firmware.

The GPIO register bank is a set of registers that are common to all PHYs
in the package. So any modification in any register of this bank affects
all PHYs of the package.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
drivers/net/phy/mscc.c

index c1b73c6348dbf0a07b340ac363f3f7562c93d195..72bbda5469591fb3b88fe45ba1879e44c04ab5a1 100644 (file)
@@ -19,6 +19,7 @@
 #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
 
 /* Microsemi VSC85xx PHY Register Pages */
@@ -40,6 +41,9 @@
 #define MSCC_PHY_EXT_CNTL_STATUS          22
 #define SMI_BROADCAST_WR_EN              BIT(0)
 
+/* Std Page Register 24 */
+#define MSCC_PHY_EXT_PHY_CNTL_2           24
+
 /* Std Page Register 28 - PHY AUX Control/Status */
 #define MIIM_AUX_CNTRL_STAT_REG                28
 #define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO (0x0004)
 #define DW8051_CLK_EN                  BIT(4)
 #define MICRO_CLK_EN                   BIT(3)
 #define MICRO_CLK_DIVIDE(x)            ((x) >> 1)
+#define MSCC_DW8051_VLD_MASK           0xf1ff
 
 /* Extended page GPIO register 09G */
 #define MSCC_TRAP_ROM_ADDR(x)          ((x) * 2 + 1)
+#define MSCC_TRAP_ROM_ADDR_SERDES_INIT 0x3eb7
 
 /* Extended page GPIO register 10G */
 #define MSCC_PATCH_RAM_ADDR(x)         (((x) + 1) * 2)
+#define MSCC_PATCH_RAM_ADDR_SERDES_INIT        0x4012
 
 /* Extended page GPIO register 11G */
 #define MSCC_INT_MEM_ADDR              11
 #define PROC_CMD_SGMII_MAC               (BIT(5) | BIT(4))
 #define PROC_CMD_QSGMII_MAC              BIT(5)
 #define PROC_CMD_NO_MAC_CONF             (0x00 << 4)
+#define PROC_CMD_1588_DEFAULT_INIT       BIT(4)
 #define PROC_CMD_NOP                     GENMASK(3, 0)
+#define PROC_CMD_PHY_INIT                (BIT(3) | BIT(1))
 #define PROC_CMD_CRC16                   BIT(3)
 #define PROC_CMD_FIBER_MEDIA_CONF        BIT(0)
 #define PROC_CMD_MCB_ACCESS_MAC_CONF     (0x0000 << 0)
 #define MSCC_PHY_TEST_PAGE_8           8
 #define TR_CLK_DISABLE                 BIT(15)
 
+#define MSCC_PHY_TEST_PAGE_9           9
+#define MSCC_PHY_TEST_PAGE_20          20
+#define MSCC_PHY_TEST_PAGE_24          24
+
 /* Token Ring Page 0x52B5 Registers */
 #define MSCC_PHY_REG_TR_ADDR_16                16
 #define MSCC_PHY_REG_TR_DATA_17                17
 #define VSC8584_REVB           0x0001
 #define MSCC_DEV_REV_MASK      GENMASK(3, 0)
 
+#define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR 0x4000
+#define MSCC_VSC8574_REVB_INT8051_FW_CRC       0x29e8
+
 #define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR        0xe800
 #define MSCC_VSC8584_REVB_INT8051_FW_CRC       0xfb48
 
@@ -373,6 +389,147 @@ static int vsc8584_micro_assert_reset(struct mii_dev *bus, int phy)
        return 0;
 }
 
+static const u8 fw_patch_vsc8574[] = {
+       0x46, 0x4a, 0x02, 0x43, 0x37, 0x02, 0x46, 0x26, 0x02, 0x46, 0x77, 0x02,
+       0x45, 0x60, 0x02, 0x45, 0xaf, 0xed, 0xff, 0xe5, 0xfc, 0x54, 0x38, 0x64,
+       0x20, 0x70, 0x08, 0x65, 0xff, 0x70, 0x04, 0xed, 0x44, 0x80, 0xff, 0x22,
+       0x8f, 0x19, 0x7b, 0xbb, 0x7d, 0x0e, 0x7f, 0x04, 0x12, 0x3d, 0xd7, 0xef,
+       0x4e, 0x60, 0x03, 0x02, 0x41, 0xf9, 0xe4, 0xf5, 0x1a, 0x74, 0x01, 0x7e,
+       0x00, 0xa8, 0x1a, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8,
+       0xf9, 0xff, 0xef, 0x55, 0x19, 0x70, 0x03, 0x02, 0x41, 0xed, 0x85, 0x1a,
+       0xfb, 0x7b, 0xbb, 0xe4, 0xfd, 0xff, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60,
+       0x03, 0x02, 0x41, 0xed, 0xe5, 0x1a, 0x54, 0x02, 0x75, 0x1d, 0x00, 0x25,
+       0xe0, 0x25, 0xe0, 0xf5, 0x1c, 0xe4, 0x78, 0xc5, 0xf6, 0xd2, 0x0a, 0x12,
+       0x41, 0xfa, 0x7b, 0xff, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef,
+       0x4e, 0x60, 0x03, 0x02, 0x41, 0xe7, 0xc2, 0x0a, 0x74, 0xc7, 0x25, 0x1a,
+       0xf9, 0x74, 0xe7, 0x25, 0x1a, 0xf8, 0xe6, 0x27, 0xf5, 0x1b, 0xe5, 0x1d,
+       0x24, 0x5b, 0x12, 0x45, 0xea, 0x12, 0x3e, 0xda, 0x7b, 0xfc, 0x7d, 0x11,
+       0x7f, 0x07, 0x12, 0x3d, 0xd7, 0x78, 0xcc, 0xef, 0xf6, 0x78, 0xc1, 0xe6,
+       0xfe, 0xef, 0xd3, 0x9e, 0x40, 0x06, 0x78, 0xcc, 0xe6, 0x78, 0xc1, 0xf6,
+       0x12, 0x41, 0xfa, 0x7b, 0xec, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7,
+       0x78, 0xcb, 0xef, 0xf6, 0xbf, 0x07, 0x06, 0x78, 0xc3, 0x76, 0x1a, 0x80,
+       0x1f, 0x78, 0xc5, 0xe6, 0xff, 0x60, 0x0f, 0xc3, 0xe5, 0x1b, 0x9f, 0xff,
+       0x78, 0xcb, 0xe6, 0x85, 0x1b, 0xf0, 0xa4, 0x2f, 0x80, 0x07, 0x78, 0xcb,
+       0xe6, 0x85, 0x1b, 0xf0, 0xa4, 0x78, 0xc3, 0xf6, 0xe4, 0x78, 0xc2, 0xf6,
+       0x78, 0xc2, 0xe6, 0xff, 0xc3, 0x08, 0x96, 0x40, 0x03, 0x02, 0x41, 0xd1,
+       0xef, 0x54, 0x03, 0x60, 0x33, 0x14, 0x60, 0x46, 0x24, 0xfe, 0x60, 0x42,
+       0x04, 0x70, 0x4b, 0xef, 0x24, 0x02, 0xff, 0xe4, 0x33, 0xfe, 0xef, 0x78,
+       0x02, 0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0xd8, 0xf8, 0xff, 0xe5, 0x1d,
+       0x24, 0x5c, 0xcd, 0xe5, 0x1c, 0x34, 0xf0, 0xcd, 0x2f, 0xff, 0xed, 0x3e,
+       0xfe, 0x12, 0x46, 0x0d, 0x7d, 0x11, 0x80, 0x0b, 0x78, 0xc2, 0xe6, 0x70,
+       0x04, 0x7d, 0x11, 0x80, 0x02, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3e, 0x9a,
+       0x8e, 0x1e, 0x8f, 0x1f, 0x80, 0x03, 0xe5, 0x1e, 0xff, 0x78, 0xc5, 0xe6,
+       0x06, 0x24, 0xcd, 0xf8, 0xa6, 0x07, 0x78, 0xc2, 0x06, 0xe6, 0xb4, 0x1a,
+       0x0a, 0xe5, 0x1d, 0x24, 0x5c, 0x12, 0x45, 0xea, 0x12, 0x3e, 0xda, 0x78,
+       0xc5, 0xe6, 0x65, 0x1b, 0x70, 0x82, 0x75, 0xdb, 0x20, 0x75, 0xdb, 0x28,
+       0x12, 0x46, 0x02, 0x12, 0x46, 0x02, 0xe5, 0x1a, 0x12, 0x45, 0xf5, 0xe5,
+       0x1a, 0xc3, 0x13, 0x12, 0x45, 0xf5, 0x78, 0xc5, 0x16, 0xe6, 0x24, 0xcd,
+       0xf8, 0xe6, 0xff, 0x7e, 0x08, 0x1e, 0xef, 0xa8, 0x06, 0x08, 0x80, 0x02,
+       0xc3, 0x13, 0xd8, 0xfc, 0xfd, 0xc4, 0x33, 0x54, 0xe0, 0xf5, 0xdb, 0xef,
+       0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x13, 0xd8, 0xfc, 0xfd, 0xc4, 0x33,
+       0x54, 0xe0, 0x44, 0x08, 0xf5, 0xdb, 0xee, 0x70, 0xd8, 0x78, 0xc5, 0xe6,
+       0x70, 0xc8, 0x75, 0xdb, 0x10, 0x02, 0x40, 0xfd, 0x78, 0xc2, 0xe6, 0xc3,
+       0x94, 0x17, 0x50, 0x0e, 0xe5, 0x1d, 0x24, 0x62, 0x12, 0x42, 0x08, 0xe5,
+       0x1d, 0x24, 0x5c, 0x12, 0x42, 0x08, 0x20, 0x0a, 0x03, 0x02, 0x40, 0x76,
+       0x05, 0x1a, 0xe5, 0x1a, 0xc3, 0x94, 0x04, 0x50, 0x03, 0x02, 0x40, 0x3a,
+       0x22, 0xe5, 0x1d, 0x24, 0x5c, 0xff, 0xe5, 0x1c, 0x34, 0xf0, 0xfe, 0x12,
+       0x46, 0x0d, 0x22, 0xff, 0xe5, 0x1c, 0x34, 0xf0, 0xfe, 0x12, 0x46, 0x0d,
+       0x22, 0xe4, 0xf5, 0x19, 0x12, 0x46, 0x43, 0x20, 0xe7, 0x1e, 0x7b, 0xfe,
+       0x12, 0x42, 0xf9, 0xef, 0xc4, 0x33, 0x33, 0x54, 0xc0, 0xff, 0xc0, 0x07,
+       0x7b, 0x54, 0x12, 0x42, 0xf9, 0xd0, 0xe0, 0x4f, 0xff, 0x74, 0x2a, 0x25,
+       0x19, 0xf8, 0xa6, 0x07, 0x12, 0x46, 0x43, 0x20, 0xe7, 0x03, 0x02, 0x42,
+       0xdf, 0x54, 0x03, 0x64, 0x03, 0x70, 0x03, 0x02, 0x42, 0xcf, 0x7b, 0xcb,
+       0x12, 0x43, 0x2c, 0x8f, 0xfb, 0x7b, 0x30, 0x7d, 0x03, 0xe4, 0xff, 0x12,
+       0x3d, 0xd7, 0xc3, 0xef, 0x94, 0x02, 0xee, 0x94, 0x00, 0x50, 0x2a, 0x12,
+       0x42, 0xec, 0xef, 0x4e, 0x70, 0x23, 0x12, 0x43, 0x04, 0x60, 0x0a, 0x12,
+       0x43, 0x12, 0x70, 0x0c, 0x12, 0x43, 0x1f, 0x70, 0x07, 0x12, 0x46, 0x39,
+       0x7b, 0x03, 0x80, 0x07, 0x12, 0x46, 0x39, 0x12, 0x46, 0x43, 0xfb, 0x7a,
+       0x00, 0x7d, 0x54, 0x80, 0x3e, 0x12, 0x42, 0xec, 0xef, 0x4e, 0x70, 0x24,
+       0x12, 0x43, 0x04, 0x60, 0x0a, 0x12, 0x43, 0x12, 0x70, 0x0f, 0x12, 0x43,
+       0x1f, 0x70, 0x0a, 0x12, 0x46, 0x39, 0xe4, 0xfb, 0xfa, 0x7d, 0xee, 0x80,
+       0x1e, 0x12, 0x46, 0x39, 0x7b, 0x01, 0x7a, 0x00, 0x7d, 0xee, 0x80, 0x13,
+       0x12, 0x46, 0x39, 0x12, 0x46, 0x43, 0x54, 0x40, 0xfe, 0xc4, 0x13, 0x13,
+       0x54, 0x03, 0xfb, 0x7a, 0x00, 0x7d, 0xee, 0x12, 0x38, 0xbd, 0x7b, 0xff,
+       0x12, 0x43, 0x2c, 0xef, 0x4e, 0x70, 0x07, 0x74, 0x2a, 0x25, 0x19, 0xf8,
+       0xe4, 0xf6, 0x05, 0x19, 0xe5, 0x19, 0xc3, 0x94, 0x02, 0x50, 0x03, 0x02,
+       0x42, 0x15, 0x22, 0xe5, 0x19, 0x24, 0x17, 0xfd, 0x7b, 0x20, 0x7f, 0x04,
+       0x12, 0x3d, 0xd7, 0x22, 0xe5, 0x19, 0x24, 0x17, 0xfd, 0x7f, 0x04, 0x12,
+       0x3d, 0xd7, 0x22, 0x7b, 0x22, 0x7d, 0x18, 0x7f, 0x06, 0x12, 0x3d, 0xd7,
+       0xef, 0x64, 0x01, 0x4e, 0x22, 0x7d, 0x1c, 0xe4, 0xff, 0x12, 0x3e, 0x9a,
+       0xef, 0x54, 0x1b, 0x64, 0x0a, 0x22, 0x7b, 0xcc, 0x7d, 0x10, 0xff, 0x12,
+       0x3d, 0xd7, 0xef, 0x64, 0x01, 0x4e, 0x22, 0xe5, 0x19, 0x24, 0x17, 0xfd,
+       0x7f, 0x04, 0x12, 0x3d, 0xd7, 0x22, 0xd2, 0x08, 0x75, 0xfb, 0x03, 0xab,
+       0x7e, 0xaa, 0x7d, 0x7d, 0x19, 0x7f, 0x03, 0x12, 0x3e, 0xda, 0xe5, 0x7e,
+       0x54, 0x0f, 0x24, 0xf3, 0x60, 0x03, 0x02, 0x43, 0xe9, 0x12, 0x46, 0x5a,
+       0x12, 0x46, 0x61, 0xd8, 0xfb, 0xff, 0x20, 0xe2, 0x35, 0x13, 0x92, 0x0c,
+       0xef, 0xa2, 0xe1, 0x92, 0x0b, 0x30, 0x0c, 0x2a, 0xe4, 0xf5, 0x10, 0x7b,
+       0xfe, 0x12, 0x43, 0xff, 0xef, 0xc4, 0x33, 0x33, 0x54, 0xc0, 0xff, 0xc0,
+       0x07, 0x7b, 0x54, 0x12, 0x43, 0xff, 0xd0, 0xe0, 0x4f, 0xff, 0x74, 0x2a,
+       0x25, 0x10, 0xf8, 0xa6, 0x07, 0x05, 0x10, 0xe5, 0x10, 0xc3, 0x94, 0x02,
+       0x40, 0xd9, 0x12, 0x46, 0x5a, 0x12, 0x46, 0x61, 0xd8, 0xfb, 0x54, 0x05,
+       0x64, 0x04, 0x70, 0x27, 0x78, 0xc4, 0xe6, 0x78, 0xc6, 0xf6, 0xe5, 0x7d,
+       0xff, 0x33, 0x95, 0xe0, 0xef, 0x54, 0x0f, 0x78, 0xc4, 0xf6, 0x12, 0x44,
+       0x0a, 0x20, 0x0c, 0x0c, 0x12, 0x46, 0x5a, 0x12, 0x46, 0x61, 0xd8, 0xfb,
+       0x13, 0x92, 0x0d, 0x22, 0xc2, 0x0d, 0x22, 0x12, 0x46, 0x5a, 0x12, 0x46,
+       0x61, 0xd8, 0xfb, 0x54, 0x05, 0x64, 0x05, 0x70, 0x1e, 0x78, 0xc4, 0x7d,
+       0xb8, 0x12, 0x43, 0xf5, 0x78, 0xc1, 0x7d, 0x74, 0x12, 0x43, 0xf5, 0xe4,
+       0x78, 0xc1, 0xf6, 0x22, 0x7b, 0x01, 0x7a, 0x00, 0x7d, 0xee, 0x7f, 0x92,
+       0x12, 0x38, 0xbd, 0x22, 0xe6, 0xfb, 0x7a, 0x00, 0x7f, 0x92, 0x12, 0x38,
+       0xbd, 0x22, 0xe5, 0x10, 0x24, 0x17, 0xfd, 0x7f, 0x04, 0x12, 0x3d, 0xd7,
+       0x22, 0x78, 0xc1, 0xe6, 0xfb, 0x7a, 0x00, 0x7d, 0x74, 0x7f, 0x92, 0x12,
+       0x38, 0xbd, 0xe4, 0x78, 0xc1, 0xf6, 0xf5, 0x11, 0x74, 0x01, 0x7e, 0x00,
+       0xa8, 0x11, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9,
+       0xff, 0x78, 0xc4, 0xe6, 0xfd, 0xef, 0x5d, 0x60, 0x44, 0x85, 0x11, 0xfb,
+       0xe5, 0x11, 0x54, 0x02, 0x25, 0xe0, 0x25, 0xe0, 0xfe, 0xe4, 0x24, 0x5b,
+       0xfb, 0xee, 0x12, 0x45, 0xed, 0x12, 0x3e, 0xda, 0x7b, 0x40, 0x7d, 0x11,
+       0x7f, 0x07, 0x12, 0x3d, 0xd7, 0x74, 0xc7, 0x25, 0x11, 0xf8, 0xa6, 0x07,
+       0x7b, 0x11, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60,
+       0x09, 0x74, 0xe7, 0x25, 0x11, 0xf8, 0x76, 0x04, 0x80, 0x07, 0x74, 0xe7,
+       0x25, 0x11, 0xf8, 0x76, 0x0a, 0x05, 0x11, 0xe5, 0x11, 0xc3, 0x94, 0x04,
+       0x40, 0x9a, 0x78, 0xc6, 0xe6, 0x70, 0x15, 0x78, 0xc4, 0xe6, 0x60, 0x10,
+       0x75, 0xd9, 0x38, 0x75, 0xdb, 0x10, 0x7d, 0xfe, 0x12, 0x44, 0xb8, 0x7d,
+       0x76, 0x12, 0x44, 0xb8, 0x79, 0xc6, 0xe7, 0x78, 0xc4, 0x66, 0xff, 0x60,
+       0x03, 0x12, 0x40, 0x25, 0x78, 0xc4, 0xe6, 0x70, 0x09, 0xfb, 0xfa, 0x7d,
+       0xfe, 0x7f, 0x8e, 0x12, 0x38, 0xbd, 0x22, 0x7b, 0x01, 0x7a, 0x00, 0x7f,
+       0x8e, 0x12, 0x38, 0xbd, 0x22, 0xe4, 0xf5, 0xfb, 0x7d, 0x1c, 0xe4, 0xff,
+       0x12, 0x3e, 0x9a, 0xad, 0x07, 0xac, 0x06, 0xec, 0x54, 0xc0, 0xff, 0xed,
+       0x54, 0x3f, 0x4f, 0xf5, 0x20, 0x30, 0x06, 0x2c, 0x30, 0x01, 0x08, 0xa2,
+       0x04, 0x72, 0x03, 0x92, 0x07, 0x80, 0x21, 0x30, 0x04, 0x06, 0x7b, 0xcc,
+       0x7d, 0x11, 0x80, 0x0d, 0x30, 0x03, 0x06, 0x7b, 0xcc, 0x7d, 0x10, 0x80,
+       0x04, 0x7b, 0x66, 0x7d, 0x16, 0xe4, 0xff, 0x12, 0x3d, 0xd7, 0xee, 0x4f,
+       0x24, 0xff, 0x92, 0x07, 0xaf, 0xfb, 0x74, 0x26, 0x2f, 0xf8, 0xe6, 0xff,
+       0xa6, 0x20, 0x20, 0x07, 0x39, 0x8f, 0x20, 0x30, 0x07, 0x34, 0x30, 0x00,
+       0x31, 0x20, 0x04, 0x2e, 0x20, 0x03, 0x2b, 0xe4, 0xf5, 0xff, 0x75, 0xfc,
+       0xc2, 0xe5, 0xfc, 0x30, 0xe0, 0xfb, 0xaf, 0xfe, 0xef, 0x20, 0xe3, 0x1a,
+       0xae, 0xfd, 0x44, 0x08, 0xf5, 0xfe, 0x75, 0xfc, 0x80, 0xe5, 0xfc, 0x30,
+       0xe0, 0xfb, 0x8f, 0xfe, 0x8e, 0xfd, 0x75, 0xfc, 0x80, 0xe5, 0xfc, 0x30,
+       0xe0, 0xfb, 0x05, 0xfb, 0xaf, 0xfb, 0xef, 0xc3, 0x94, 0x04, 0x50, 0x03,
+       0x02, 0x44, 0xc5, 0xe4, 0xf5, 0xfb, 0x22, 0xe5, 0x7e, 0x54, 0x0f, 0x64,
+       0x01, 0x70, 0x23, 0xe5, 0x7e, 0x30, 0xe4, 0x1e, 0x90, 0x47, 0xd0, 0xe0,
+       0x44, 0x02, 0xf0, 0x54, 0xfb, 0xf0, 0x90, 0x47, 0xd4, 0xe0, 0x44, 0x04,
+       0xf0, 0x7b, 0x03, 0x7d, 0x5b, 0x7f, 0x5d, 0x12, 0x36, 0x29, 0x7b, 0x0e,
+       0x80, 0x1c, 0x90, 0x47, 0xd0, 0xe0, 0x54, 0xfd, 0xf0, 0x44, 0x04, 0xf0,
+       0x90, 0x47, 0xd4, 0xe0, 0x54, 0xfb, 0xf0, 0x7b, 0x02, 0x7d, 0x5b, 0x7f,
+       0x5d, 0x12, 0x36, 0x29, 0x7b, 0x06, 0x7d, 0x60, 0x7f, 0x63, 0x12, 0x36,
+       0x29, 0x22, 0xe5, 0x7e, 0x30, 0xe5, 0x35, 0x30, 0xe4, 0x0b, 0x7b, 0x02,
+       0x7d, 0x33, 0x7f, 0x35, 0x12, 0x36, 0x29, 0x80, 0x10, 0x7b, 0x01, 0x7d,
+       0x33, 0x7f, 0x35, 0x12, 0x36, 0x29, 0x90, 0x47, 0xd2, 0xe0, 0x44, 0x04,
+       0xf0, 0x90, 0x47, 0xd2, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x47, 0xd1, 0xe0,
+       0x44, 0x10, 0xf0, 0x7b, 0x05, 0x7d, 0x84, 0x7f, 0x86, 0x12, 0x36, 0x29,
+       0x22, 0xfb, 0xe5, 0x1c, 0x34, 0xf0, 0xfa, 0x7d, 0x10, 0x7f, 0x07, 0x22,
+       0x54, 0x01, 0xc4, 0x33, 0x54, 0xe0, 0xf5, 0xdb, 0x44, 0x08, 0xf5, 0xdb,
+       0x22, 0xf5, 0xdb, 0x75, 0xdb, 0x08, 0xf5, 0xdb, 0x75, 0xdb, 0x08, 0x22,
+       0xab, 0x07, 0xaa, 0x06, 0x7d, 0x10, 0x7f, 0x07, 0x12, 0x3e, 0xda, 0x7b,
+       0xff, 0x7d, 0x10, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60, 0xf3,
+       0x22, 0x12, 0x44, 0xc2, 0x30, 0x0c, 0x03, 0x12, 0x42, 0x12, 0x78, 0xc4,
+       0xe6, 0xff, 0x60, 0x03, 0x12, 0x40, 0x25, 0x22, 0xe5, 0x19, 0x24, 0x17,
+       0x54, 0x1f, 0x44, 0x80, 0xff, 0x22, 0x74, 0x2a, 0x25, 0x19, 0xf8, 0xe6,
+       0x22, 0x12, 0x46, 0x72, 0x12, 0x46, 0x68, 0x90, 0x47, 0xfa, 0xe0, 0x54,
+       0xf8, 0x44, 0x02, 0xf0, 0x22, 0xe5, 0x7e, 0xae, 0x7d, 0x78, 0x04, 0x22,
+       0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0x22, 0xe4, 0x78, 0xc4, 0xf6, 0xc2,
+       0x0d, 0x78, 0xc1, 0xf6, 0x22, 0xc2, 0x0c, 0xc2, 0x0b, 0x22, 0x22,
+};
+
 static const u8 fw_patch_vsc8584[] = {
        0xe8, 0x59, 0x02, 0xe8, 0x12, 0x02, 0xe8, 0x42, 0x02, 0xe8, 0x5a, 0x02,
        0xe8, 0x5b, 0x02, 0xe8, 0x5c, 0xe5, 0x69, 0x54, 0x0f, 0x24, 0xf7, 0x60,
@@ -451,6 +608,247 @@ static int vsc8584_patch_fw(struct mii_dev *bus, int phy, const u8 *fw_patch,
        return 0;
 }
 
+static bool vsc8574_is_serdes_init(struct mii_dev *bus, int phy)
+{
+       u16 reg;
+       bool ret;
+
+       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_GPIO);
+
+       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_TRAP_ROM_ADDR(1));
+       if (reg != MSCC_TRAP_ROM_ADDR_SERDES_INIT) {
+               ret = false;
+               goto out;
+       }
+
+       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_PATCH_RAM_ADDR(1));
+       if (reg != MSCC_PATCH_RAM_ADDR_SERDES_INIT) {
+               ret = false;
+               goto out;
+       }
+
+       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
+       if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
+               ret = false;
+               goto out;
+       }
+
+       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, 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:
+       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_GPIO);
+
+       return ret;
+}
+
+static int vsc8574_config_pre_init(struct phy_device *phydev)
+{
+       struct mii_dev *bus = phydev->bus;
+       u16 crc, reg, phy0, addr;
+       bool serdes_init;
+       int ret;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_EXT1);
+       addr = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_4);
+       addr >>= PHY_CNTL_4_ADDR_POS;
+
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_ACTIPHY_CNTL);
+       if (reg & PHY_ADDR_REVERSED)
+               phy0 = phydev->addr + addr;
+       else
+               phy0 = phydev->addr - addr;
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_STD);
+
+       /* all writes below are broadcasted to all PHYs in the same package */
+       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
+       reg |= SMI_BROADCAST_WR_EN;
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+       /*
+        * 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".
+        */
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_TEST);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_20, 0x4320);
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_24, 0x0c00);
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_9, 0x18ca);
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_5, 0x1b20);
+
+       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
+       reg |= TR_CLK_DISABLE;
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_TR);
+
+       vsc8584_csr_write(bus, phy0, 0x0fae, 0x000401bd);
+       vsc8584_csr_write(bus, phy0, 0x0fac, 0x000f000f);
+       vsc8584_csr_write(bus, phy0, 0x17a0, 0x00a0f147);
+       vsc8584_csr_write(bus, phy0, 0x0fe4, 0x00052f54);
+       vsc8584_csr_write(bus, phy0, 0x1792, 0x0027303d);
+       vsc8584_csr_write(bus, phy0, 0x07fe, 0x00000704);
+       vsc8584_csr_write(bus, phy0, 0x0fe0, 0x00060150);
+       vsc8584_csr_write(bus, phy0, 0x0f82, 0x0012b00a);
+       vsc8584_csr_write(bus, phy0, 0x0f80, 0x00000d74);
+       vsc8584_csr_write(bus, phy0, 0x02e0, 0x00000012);
+       vsc8584_csr_write(bus, phy0, 0x03a2, 0x00050208);
+       vsc8584_csr_write(bus, phy0, 0x03b2, 0x00009186);
+       vsc8584_csr_write(bus, phy0, 0x0fb0, 0x000e3700);
+       vsc8584_csr_write(bus, phy0, 0x1688, 0x00049f81);
+       vsc8584_csr_write(bus, phy0, 0x0fd2, 0x0000ffff);
+       vsc8584_csr_write(bus, phy0, 0x168a, 0x00039fa2);
+       vsc8584_csr_write(bus, phy0, 0x1690, 0x0020640b);
+       vsc8584_csr_write(bus, phy0, 0x0258, 0x00002220);
+       vsc8584_csr_write(bus, phy0, 0x025a, 0x00002a20);
+       vsc8584_csr_write(bus, phy0, 0x025c, 0x00003060);
+       vsc8584_csr_write(bus, phy0, 0x025e, 0x00003fa0);
+       vsc8584_csr_write(bus, phy0, 0x03a6, 0x0000e0f0);
+       vsc8584_csr_write(bus, phy0, 0x0f92, 0x00001489);
+       vsc8584_csr_write(bus, phy0, 0x16a2, 0x00007000);
+       vsc8584_csr_write(bus, phy0, 0x16a6, 0x00071448);
+       vsc8584_csr_write(bus, phy0, 0x16a0, 0x00eeffdd);
+       vsc8584_csr_write(bus, phy0, 0x0fe8, 0x0091b06c);
+       vsc8584_csr_write(bus, phy0, 0x0fea, 0x00041600);
+       vsc8584_csr_write(bus, phy0, 0x16b0, 0x00eeff00);
+       vsc8584_csr_write(bus, phy0, 0x16b2, 0x00007000);
+       vsc8584_csr_write(bus, phy0, 0x16b4, 0x00000814);
+       vsc8584_csr_write(bus, phy0, 0x0f90, 0x00688980);
+       vsc8584_csr_write(bus, phy0, 0x03a4, 0x0000d8f0);
+       vsc8584_csr_write(bus, phy0, 0x0fc0, 0x00000400);
+       vsc8584_csr_write(bus, phy0, 0x07fa, 0x0050100f);
+       vsc8584_csr_write(bus, phy0, 0x0796, 0x00000003);
+       vsc8584_csr_write(bus, phy0, 0x07f8, 0x00c3ff98);
+       vsc8584_csr_write(bus, phy0, 0x0fa4, 0x0018292a);
+       vsc8584_csr_write(bus, phy0, 0x168c, 0x00d2c46f);
+       vsc8584_csr_write(bus, phy0, 0x17a2, 0x00000620);
+       vsc8584_csr_write(bus, phy0, 0x16a4, 0x0013132f);
+       vsc8584_csr_write(bus, phy0, 0x16a8, 0x00000000);
+       vsc8584_csr_write(bus, phy0, 0x0ffc, 0x00c0a028);
+       vsc8584_csr_write(bus, phy0, 0x0fec, 0x00901c09);
+       vsc8584_csr_write(bus, phy0, 0x0fee, 0x0004a6a1);
+       vsc8584_csr_write(bus, phy0, 0x0ffe, 0x00b01807);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                       MSCC_PHY_PAGE_EXT2);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_TR);
+
+       vsc8584_csr_write(bus, phy0, 0x0486, 0x0008a518);
+       vsc8584_csr_write(bus, phy0, 0x0488, 0x006dc696);
+       vsc8584_csr_write(bus, phy0, 0x048a, 0x00000912);
+       vsc8584_csr_write(bus, phy0, 0x048e, 0x00000db6);
+       vsc8584_csr_write(bus, phy0, 0x049c, 0x00596596);
+       vsc8584_csr_write(bus, phy0, 0x049e, 0x00000514);
+       vsc8584_csr_write(bus, phy0, 0x04a2, 0x00410280);
+       vsc8584_csr_write(bus, phy0, 0x04a4, 0x00000000);
+       vsc8584_csr_write(bus, phy0, 0x04a6, 0x00000000);
+       vsc8584_csr_write(bus, phy0, 0x04a8, 0x00000000);
+       vsc8584_csr_write(bus, phy0, 0x04aa, 0x00000000);
+       vsc8584_csr_write(bus, phy0, 0x04ae, 0x007df7dd);
+       vsc8584_csr_write(bus, phy0, 0x04b0, 0x006d95d4);
+       vsc8584_csr_write(bus, phy0, 0x04b2, 0x00492410);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_TEST);
+
+       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
+       reg &= ~TR_CLK_DISABLE;
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                       MSCC_PHY_PAGE_STD);
+
+       /* end of write broadcasting */
+       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
+       reg &= ~SMI_BROADCAST_WR_EN;
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+       ret = vsc8584_get_fw_crc(bus, phy0,
+                                MSCC_VSC8574_REVB_INT8051_FW_START_ADDR, &crc,
+                                fw_patch_vsc8574,
+                                ARRAY_SIZE(fw_patch_vsc8574));
+       if (ret)
+               goto out;
+
+       if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
+               serdes_init = vsc8574_is_serdes_init(bus, phy0);
+
+               if (!serdes_init) {
+                       ret = vsc8584_micro_assert_reset(bus, phy0);
+                       if (ret) {
+                               pr_err("failed to assert reset of micro\n");
+                               return ret;
+                       }
+               }
+       } else {
+               pr_debug("FW CRC is not the expected one, patching FW\n");
+
+               serdes_init = false;
+
+               if (vsc8584_patch_fw(bus, phy0, fw_patch_vsc8574,
+                                    ARRAY_SIZE(fw_patch_vsc8574)))
+                       pr_warn("failed to patch FW, expect non-optimal device\n");
+       }
+
+       if (!serdes_init) {
+               bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                               MSCC_PHY_PAGE_GPIO);
+
+               bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_TRAP_ROM_ADDR(1),
+                          MSCC_TRAP_ROM_ADDR_SERDES_INIT);
+               bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PATCH_RAM_ADDR(1),
+                          MSCC_PATCH_RAM_ADDR_SERDES_INIT);
+
+               bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL,
+                               EN_PATCH_RAM_TRAP_ADDR(1));
+
+               vsc8584_micro_deassert_reset(bus, phy0, false);
+
+               ret = vsc8584_get_fw_crc(bus, phy0,
+                                        MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
+                                        &crc, fw_patch_vsc8574,
+                                        ARRAY_SIZE(fw_patch_vsc8574));
+               if (ret)
+                       goto out;
+
+               if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
+                       pr_warn("FW CRC after patching is not the expected one, expect non-optimal device\n");
+       }
+
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                  MSCC_PHY_PAGE_GPIO);
+
+       ret = vsc8584_cmd(bus, phy0, PROC_CMD_1588_DEFAULT_INIT |
+                         PROC_CMD_PHY_INIT);
+
+out:
+       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                       MSCC_PHY_PAGE_STD);
+
+       return ret;
+}
+
 static int vsc8584_config_pre_init(struct phy_device *phydev)
 {
        struct mii_dev *bus = phydev->bus;
@@ -1010,6 +1408,17 @@ static int vsc8584_config_init(struct phy_device *phydev)
        return genphy_config(phydev);
 }
 
+static struct vsc85xx_priv vsc8574_priv = {
+       .config_pre = vsc8574_config_pre_init,
+};
+
+static int vsc8574_config(struct phy_device *phydev)
+{
+       phydev->priv = &vsc8574_priv;
+
+       return vsc8584_config_init(phydev);
+}
+
 static struct vsc85xx_priv vsc8584_priv = {
        .config_pre = vsc8584_config_pre_init,
 };
@@ -1061,6 +1470,16 @@ static struct phy_driver VSC8541_driver = {
        .shutdown = &genphy_shutdown,
 };
 
+static struct phy_driver VSC8574_driver = {
+       .name = "Microsemi VSC8574",
+       .uid = PHY_ID_VSC8574,
+       .mask = 0x000ffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &vsc8574_config,
+       .startup = &mscc_startup,
+       .shutdown = &genphy_shutdown,
+};
+
 static struct phy_driver VSC8584_driver = {
        .name = "Microsemi VSC8584",
        .uid = PHY_ID_VSC8584,
@@ -1077,6 +1496,7 @@ int phy_mscc_init(void)
        phy_register(&VSC8531_driver);
        phy_register(&VSC8540_driver);
        phy_register(&VSC8541_driver);
+       phy_register(&VSC8574_driver);
        phy_register(&VSC8584_driver);
 
        return 0;