@@ -65,6 +65,8 @@ enum rgmii_rx_clock_delay {
65
65
#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX 7
66
66
#define MEDIA_OP_MODE_POS 8
67
67
68
+ #define MSCC_PHY_EXT_PHY_CNTL_2 24
69
+
68
70
#define MII_VSC85XX_INT_MASK 25
69
71
#define MII_VSC85XX_INT_MASK_MASK 0xa000
70
72
#define MII_VSC85XX_INT_MASK_WOL 0x0040
@@ -151,6 +153,7 @@ enum rgmii_rx_clock_delay {
151
153
#define DW8051_CLK_EN 0x0010
152
154
#define MICRO_CLK_EN 0x0008
153
155
#define MICRO_CLK_DIVIDE (x ) ((x) >> 1)
156
+ #define MSCC_DW8051_VLD_MASK 0xf1ff
154
157
155
158
/* x Address in range 1-4 */
156
159
#define MSCC_TRAP_ROM_ADDR (x ) ((x) * 2 + 1)
@@ -184,7 +187,9 @@ enum rgmii_rx_clock_delay {
184
187
#define PROC_CMD_SGMII_MAC 0x0030
185
188
#define PROC_CMD_QSGMII_MAC 0x0020
186
189
#define PROC_CMD_NO_MAC_CONF 0x0000
190
+ #define PROC_CMD_1588_DEFAULT_INIT 0x0010
187
191
#define PROC_CMD_NOP 0x000f
192
+ #define PROC_CMD_PHY_INIT 0x000a
188
193
#define PROC_CMD_CRC16 0x0008
189
194
#define PROC_CMD_FIBER_MEDIA_CONF 0x0001
190
195
#define PROC_CMD_MCB_ACCESS_MAC_CONF 0x0000
@@ -198,6 +203,9 @@ enum rgmii_rx_clock_delay {
198
203
/* Test page Registers */
199
204
#define MSCC_PHY_TEST_PAGE_5 5
200
205
#define MSCC_PHY_TEST_PAGE_8 8
206
+ #define MSCC_PHY_TEST_PAGE_9 9
207
+ #define MSCC_PHY_TEST_PAGE_20 20
208
+ #define MSCC_PHY_TEST_PAGE_24 24
201
209
202
210
/* Token ring page Registers */
203
211
#define MSCC_PHY_TR_CNTL 16
@@ -211,6 +219,7 @@ enum rgmii_rx_clock_delay {
211
219
#define PHY_ID_VSC8531 0x00070570
212
220
#define PHY_ID_VSC8540 0x00070760
213
221
#define PHY_ID_VSC8541 0x00070770
222
+ #define PHY_ID_VSC8574 0x000704a0
214
223
#define PHY_ID_VSC8584 0x000707c0
215
224
216
225
#define MSCC_VDDMAC_1500 1500
@@ -258,6 +267,10 @@ enum rgmii_rx_clock_delay {
258
267
#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR 0xe800
259
268
#define MSCC_VSC8584_REVB_INT8051_FW_CRC 0xfb48
260
269
270
+ #define MSCC_VSC8574_REVB_INT8051_FW "mscc_vsc8574_revb_int8051_29e8.bin"
271
+ #define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR 0x4000
272
+ #define MSCC_VSC8574_REVB_INT8051_FW_CRC 0x29e8
273
+
261
274
#define VSC8584_REVB 0x0001
262
275
#define MSCC_DEV_REV_MASK GENMASK(3, 0)
263
276
@@ -1087,6 +1100,250 @@ static int vsc8584_patch_fw(struct phy_device *phydev,
1087
1100
return 0 ;
1088
1101
}
1089
1102
1103
+ /* bus->mdio_lock should be locked when using this function */
1104
+ static bool vsc8574_is_serdes_init (struct phy_device * phydev )
1105
+ {
1106
+ u16 reg ;
1107
+ bool ret ;
1108
+
1109
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS ,
1110
+ MSCC_PHY_PAGE_EXTENDED_GPIO );
1111
+
1112
+ reg = phy_base_read (phydev , MSCC_TRAP_ROM_ADDR (1 ));
1113
+ if (reg != 0x3eb7 ) {
1114
+ ret = false;
1115
+ goto out ;
1116
+ }
1117
+
1118
+ reg = phy_base_read (phydev , MSCC_PATCH_RAM_ADDR (1 ));
1119
+ if (reg != 0x4012 ) {
1120
+ ret = false;
1121
+ goto out ;
1122
+ }
1123
+
1124
+ reg = phy_base_read (phydev , MSCC_INT_MEM_CNTL );
1125
+ if (reg != EN_PATCH_RAM_TRAP_ADDR (1 )) {
1126
+ ret = false;
1127
+ goto out ;
1128
+ }
1129
+
1130
+ reg = phy_base_read (phydev , MSCC_DW8051_CNTL_STATUS );
1131
+ if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
1132
+ MICRO_CLK_EN ) != (reg & MSCC_DW8051_VLD_MASK )) {
1133
+ ret = false;
1134
+ goto out ;
1135
+ }
1136
+
1137
+ ret = true;
1138
+ out :
1139
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_STANDARD );
1140
+
1141
+ return ret ;
1142
+ }
1143
+
1144
+ /* bus->mdio_lock should be locked when using this function */
1145
+ static int vsc8574_config_pre_init (struct phy_device * phydev )
1146
+ {
1147
+ const struct reg_val pre_init1 [] = {
1148
+ {0x0fae , 0x000401bd },
1149
+ {0x0fac , 0x000f000f },
1150
+ {0x17a0 , 0x00a0f147 },
1151
+ {0x0fe4 , 0x00052f54 },
1152
+ {0x1792 , 0x0027303d },
1153
+ {0x07fe , 0x00000704 },
1154
+ {0x0fe0 , 0x00060150 },
1155
+ {0x0f82 , 0x0012b00a },
1156
+ {0x0f80 , 0x00000d74 },
1157
+ {0x02e0 , 0x00000012 },
1158
+ {0x03a2 , 0x00050208 },
1159
+ {0x03b2 , 0x00009186 },
1160
+ {0x0fb0 , 0x000e3700 },
1161
+ {0x1688 , 0x00049f81 },
1162
+ {0x0fd2 , 0x0000ffff },
1163
+ {0x168a , 0x00039fa2 },
1164
+ {0x1690 , 0x0020640b },
1165
+ {0x0258 , 0x00002220 },
1166
+ {0x025a , 0x00002a20 },
1167
+ {0x025c , 0x00003060 },
1168
+ {0x025e , 0x00003fa0 },
1169
+ {0x03a6 , 0x0000e0f0 },
1170
+ {0x0f92 , 0x00001489 },
1171
+ {0x16a2 , 0x00007000 },
1172
+ {0x16a6 , 0x00071448 },
1173
+ {0x16a0 , 0x00eeffdd },
1174
+ {0x0fe8 , 0x0091b06c },
1175
+ {0x0fea , 0x00041600 },
1176
+ {0x16b0 , 0x00eeff00 },
1177
+ {0x16b2 , 0x00007000 },
1178
+ {0x16b4 , 0x00000814 },
1179
+ {0x0f90 , 0x00688980 },
1180
+ {0x03a4 , 0x0000d8f0 },
1181
+ {0x0fc0 , 0x00000400 },
1182
+ {0x07fa , 0x0050100f },
1183
+ {0x0796 , 0x00000003 },
1184
+ {0x07f8 , 0x00c3ff98 },
1185
+ {0x0fa4 , 0x0018292a },
1186
+ {0x168c , 0x00d2c46f },
1187
+ {0x17a2 , 0x00000620 },
1188
+ {0x16a4 , 0x0013132f },
1189
+ {0x16a8 , 0x00000000 },
1190
+ {0x0ffc , 0x00c0a028 },
1191
+ {0x0fec , 0x00901c09 },
1192
+ {0x0fee , 0x0004a6a1 },
1193
+ {0x0ffe , 0x00b01807 },
1194
+ };
1195
+ const struct reg_val pre_init2 [] = {
1196
+ {0x0486 , 0x0008a518 },
1197
+ {0x0488 , 0x006dc696 },
1198
+ {0x048a , 0x00000912 },
1199
+ {0x048e , 0x00000db6 },
1200
+ {0x049c , 0x00596596 },
1201
+ {0x049e , 0x00000514 },
1202
+ {0x04a2 , 0x00410280 },
1203
+ {0x04a4 , 0x00000000 },
1204
+ {0x04a6 , 0x00000000 },
1205
+ {0x04a8 , 0x00000000 },
1206
+ {0x04aa , 0x00000000 },
1207
+ {0x04ae , 0x007df7dd },
1208
+ {0x04b0 , 0x006d95d4 },
1209
+ {0x04b2 , 0x00492410 },
1210
+ };
1211
+ struct device * dev = & phydev -> mdio .dev ;
1212
+ const struct firmware * fw ;
1213
+ unsigned int i ;
1214
+ u16 crc , reg ;
1215
+ bool serdes_init ;
1216
+ int ret ;
1217
+
1218
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_STANDARD );
1219
+
1220
+ /* all writes below are broadcasted to all PHYs in the same package */
1221
+ reg = phy_base_read (phydev , MSCC_PHY_EXT_CNTL_STATUS );
1222
+ reg |= SMI_BROADCAST_WR_EN ;
1223
+ phy_base_write (phydev , MSCC_PHY_EXT_CNTL_STATUS , reg );
1224
+
1225
+ phy_base_write (phydev , MII_VSC85XX_INT_MASK , 0 );
1226
+
1227
+ /* The below register writes are tweaking analog and electrical
1228
+ * configuration that were determined through characterization by PHY
1229
+ * engineers. These don't mean anything more than "these are the best
1230
+ * values".
1231
+ */
1232
+ phy_base_write (phydev , MSCC_PHY_EXT_PHY_CNTL_2 , 0x0040 );
1233
+
1234
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_TEST );
1235
+
1236
+ phy_base_write (phydev , MSCC_PHY_TEST_PAGE_20 , 0x4320 );
1237
+ phy_base_write (phydev , MSCC_PHY_TEST_PAGE_24 , 0x0c00 );
1238
+ phy_base_write (phydev , MSCC_PHY_TEST_PAGE_9 , 0x18ca );
1239
+ phy_base_write (phydev , MSCC_PHY_TEST_PAGE_5 , 0x1b20 );
1240
+
1241
+ reg = phy_base_read (phydev , MSCC_PHY_TEST_PAGE_8 );
1242
+ reg |= 0x8000 ;
1243
+ phy_base_write (phydev , MSCC_PHY_TEST_PAGE_8 , reg );
1244
+
1245
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_TR );
1246
+
1247
+ for (i = 0 ; i < ARRAY_SIZE (pre_init1 ); i ++ )
1248
+ vsc8584_csr_write (phydev , pre_init1 [i ].reg , pre_init1 [i ].val );
1249
+
1250
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_EXTENDED_2 );
1251
+
1252
+ phy_base_write (phydev , MSCC_PHY_CU_PMD_TX_CNTL , 0x028e );
1253
+
1254
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_TR );
1255
+
1256
+ for (i = 0 ; i < ARRAY_SIZE (pre_init2 ); i ++ )
1257
+ vsc8584_csr_write (phydev , pre_init2 [i ].reg , pre_init2 [i ].val );
1258
+
1259
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_TEST );
1260
+
1261
+ reg = phy_base_read (phydev , MSCC_PHY_TEST_PAGE_8 );
1262
+ reg &= ~0x8000 ;
1263
+ phy_base_write (phydev , MSCC_PHY_TEST_PAGE_8 , reg );
1264
+
1265
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_STANDARD );
1266
+
1267
+ /* end of write broadcasting */
1268
+ reg = phy_base_read (phydev , MSCC_PHY_EXT_CNTL_STATUS );
1269
+ reg &= ~SMI_BROADCAST_WR_EN ;
1270
+ phy_base_write (phydev , MSCC_PHY_EXT_CNTL_STATUS , reg );
1271
+
1272
+ ret = request_firmware (& fw , MSCC_VSC8574_REVB_INT8051_FW , dev );
1273
+ if (ret ) {
1274
+ dev_err (dev , "failed to load firmware %s, ret: %d\n" ,
1275
+ MSCC_VSC8574_REVB_INT8051_FW , ret );
1276
+ return ret ;
1277
+ }
1278
+
1279
+ /* Add one byte to size for the one added by the patch_fw function */
1280
+ ret = vsc8584_get_fw_crc (phydev ,
1281
+ MSCC_VSC8574_REVB_INT8051_FW_START_ADDR ,
1282
+ fw -> size + 1 , & crc );
1283
+ if (ret )
1284
+ goto out ;
1285
+
1286
+ if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC ) {
1287
+ serdes_init = vsc8574_is_serdes_init (phydev );
1288
+
1289
+ if (!serdes_init ) {
1290
+ ret = vsc8584_micro_assert_reset (phydev );
1291
+ if (ret ) {
1292
+ dev_err (dev ,
1293
+ "%s: failed to assert reset of micro\n" ,
1294
+ __func__ );
1295
+ return ret ;
1296
+ }
1297
+ }
1298
+ } else {
1299
+ dev_dbg (dev , "FW CRC is not the expected one, patching FW\n" );
1300
+
1301
+ serdes_init = false;
1302
+
1303
+ if (vsc8584_patch_fw (phydev , fw ))
1304
+ dev_warn (dev ,
1305
+ "failed to patch FW, expect non-optimal device\n" );
1306
+ }
1307
+
1308
+ if (!serdes_init ) {
1309
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS ,
1310
+ MSCC_PHY_PAGE_EXTENDED_GPIO );
1311
+
1312
+ phy_base_write (phydev , MSCC_TRAP_ROM_ADDR (1 ), 0x3eb7 );
1313
+ phy_base_write (phydev , MSCC_PATCH_RAM_ADDR (1 ), 0x4012 );
1314
+ phy_base_write (phydev , MSCC_INT_MEM_CNTL ,
1315
+ EN_PATCH_RAM_TRAP_ADDR (1 ));
1316
+
1317
+ vsc8584_micro_deassert_reset (phydev , false);
1318
+
1319
+ /* Add one byte to size for the one added by the patch_fw
1320
+ * function
1321
+ */
1322
+ ret = vsc8584_get_fw_crc (phydev ,
1323
+ MSCC_VSC8574_REVB_INT8051_FW_START_ADDR ,
1324
+ fw -> size + 1 , & crc );
1325
+ if (ret )
1326
+ goto out ;
1327
+
1328
+ if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC )
1329
+ dev_warn (dev ,
1330
+ "FW CRC after patching is not the expected one, expect non-optimal device\n" );
1331
+ }
1332
+
1333
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS ,
1334
+ MSCC_PHY_PAGE_EXTENDED_GPIO );
1335
+
1336
+ ret = vsc8584_cmd (phydev , PROC_CMD_1588_DEFAULT_INIT |
1337
+ PROC_CMD_PHY_INIT );
1338
+
1339
+ out :
1340
+ phy_base_write (phydev , MSCC_EXT_PAGE_ACCESS , MSCC_PHY_PAGE_STANDARD );
1341
+
1342
+ release_firmware (fw );
1343
+
1344
+ return ret ;
1345
+ }
1346
+
1090
1347
/* bus->mdio_lock should be locked when using this function */
1091
1348
static int vsc8584_config_pre_init (struct phy_device * phydev )
1092
1349
{
@@ -1310,7 +1567,15 @@ static int vsc8584_config_init(struct phy_device *phydev)
1310
1567
* in this pre-init function.
1311
1568
*/
1312
1569
if (!vsc8584_is_pkg_init (phydev , val & PHY_ADDR_REVERSED ? 1 : 0 )) {
1313
- ret = vsc8584_config_pre_init (phydev );
1570
+ if ((phydev -> phy_id & phydev -> drv -> phy_id_mask ) ==
1571
+ (PHY_ID_VSC8574 & phydev -> drv -> phy_id_mask ))
1572
+ ret = vsc8574_config_pre_init (phydev );
1573
+ else if ((phydev -> phy_id & phydev -> drv -> phy_id_mask ) ==
1574
+ (PHY_ID_VSC8584 & phydev -> drv -> phy_id_mask ))
1575
+ ret = vsc8584_config_pre_init (phydev );
1576
+ else
1577
+ ret = - EINVAL ;
1578
+
1314
1579
if (ret )
1315
1580
goto err ;
1316
1581
}
@@ -1476,6 +1741,31 @@ static int vsc85xx_read_status(struct phy_device *phydev)
1476
1741
return genphy_read_status (phydev );
1477
1742
}
1478
1743
1744
+ static int vsc8574_probe (struct phy_device * phydev )
1745
+ {
1746
+ struct vsc8531_private * vsc8531 ;
1747
+ u32 default_mode [4 ] = {VSC8531_LINK_1000_ACTIVITY ,
1748
+ VSC8531_LINK_100_ACTIVITY , VSC8531_LINK_ACTIVITY ,
1749
+ VSC8531_DUPLEX_COLLISION };
1750
+
1751
+ vsc8531 = devm_kzalloc (& phydev -> mdio .dev , sizeof (* vsc8531 ), GFP_KERNEL );
1752
+ if (!vsc8531 )
1753
+ return - ENOMEM ;
1754
+
1755
+ phydev -> priv = vsc8531 ;
1756
+
1757
+ vsc8531 -> nleds = 4 ;
1758
+ vsc8531 -> supp_led_modes = VSC8584_SUPP_LED_MODES ;
1759
+ vsc8531 -> hw_stats = vsc8584_hw_stats ;
1760
+ vsc8531 -> nstats = ARRAY_SIZE (vsc8584_hw_stats );
1761
+ vsc8531 -> stats = devm_kmalloc_array (& phydev -> mdio .dev , vsc8531 -> nstats ,
1762
+ sizeof (u64 ), GFP_KERNEL );
1763
+ if (!vsc8531 -> stats )
1764
+ return - ENOMEM ;
1765
+
1766
+ return vsc85xx_dt_led_modes_get (phydev , default_mode );
1767
+ }
1768
+
1479
1769
static int vsc8584_probe (struct phy_device * phydev )
1480
1770
{
1481
1771
struct vsc8531_private * vsc8531 ;
@@ -1642,6 +1932,33 @@ static struct phy_driver vsc85xx_driver[] = {
1642
1932
.get_strings = & vsc85xx_get_strings ,
1643
1933
.get_stats = & vsc85xx_get_stats ,
1644
1934
},
1935
+ {
1936
+ .phy_id = PHY_ID_VSC8574 ,
1937
+ .name = "Microsemi GE VSC8574 SyncE" ,
1938
+ .phy_id_mask = 0xfffffff0 ,
1939
+ .features = PHY_GBIT_FEATURES ,
1940
+ .flags = PHY_HAS_INTERRUPT ,
1941
+ .soft_reset = & genphy_soft_reset ,
1942
+ .config_init = & vsc8584_config_init ,
1943
+ .config_aneg = & vsc85xx_config_aneg ,
1944
+ .aneg_done = & genphy_aneg_done ,
1945
+ .read_status = & vsc85xx_read_status ,
1946
+ .ack_interrupt = & vsc85xx_ack_interrupt ,
1947
+ .config_intr = & vsc85xx_config_intr ,
1948
+ .did_interrupt = & vsc8584_did_interrupt ,
1949
+ .suspend = & genphy_suspend ,
1950
+ .resume = & genphy_resume ,
1951
+ .probe = & vsc8574_probe ,
1952
+ .set_wol = & vsc85xx_wol_set ,
1953
+ .get_wol = & vsc85xx_wol_get ,
1954
+ .get_tunable = & vsc85xx_get_tunable ,
1955
+ .set_tunable = & vsc85xx_set_tunable ,
1956
+ .read_page = & vsc85xx_phy_read_page ,
1957
+ .write_page = & vsc85xx_phy_write_page ,
1958
+ .get_sset_count = & vsc85xx_get_sset_count ,
1959
+ .get_strings = & vsc85xx_get_strings ,
1960
+ .get_stats = & vsc85xx_get_stats ,
1961
+ },
1645
1962
{
1646
1963
.phy_id = PHY_ID_VSC8584 ,
1647
1964
.name = "Microsemi GE VSC8584 SyncE" ,
@@ -1677,6 +1994,7 @@ static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
1677
1994
{ PHY_ID_VSC8531 , 0xfffffff0 , },
1678
1995
{ PHY_ID_VSC8540 , 0xfffffff0 , },
1679
1996
{ PHY_ID_VSC8541 , 0xfffffff0 , },
1997
+ { PHY_ID_VSC8574 , 0xfffffff0 , },
1680
1998
{ PHY_ID_VSC8584 , 0xfffffff0 , },
1681
1999
{ }
1682
2000
};
0 commit comments