blob: 3949fe299b18ab8efd6cf903f093323d5a055fb4 [file] [log] [blame]
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301/*
2 * Driver for Microsemi VSC85xx PHYs
3 *
4 * Author: Nagaraju Lakkaraju
5 * License: Dual MIT/GPL
6 * Copyright (c) 2016 Microsemi Corporation
7 */
8
Quentin Schulza5afc162018-10-08 12:14:42 +02009#include <linux/firmware.h>
10#include <linux/jiffies.h>
Raju Lakkarajud50736a2016-08-05 17:54:21 +053011#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/mdio.h>
14#include <linux/mii.h>
15#include <linux/phy.h>
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +053016#include <linux/of.h>
Raju Lakkaraju0a55c122016-10-05 14:19:27 +053017#include <linux/netdevice.h>
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +053018#include <dt-bindings/net/mscc-phy-vsc8531.h>
Raju Lakkarajud50736a2016-08-05 17:54:21 +053019
20enum rgmii_rx_clock_delay {
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053021 RGMII_RX_CLK_DELAY_0_2_NS = 0,
22 RGMII_RX_CLK_DELAY_0_8_NS = 1,
23 RGMII_RX_CLK_DELAY_1_1_NS = 2,
24 RGMII_RX_CLK_DELAY_1_7_NS = 3,
25 RGMII_RX_CLK_DELAY_2_0_NS = 4,
26 RGMII_RX_CLK_DELAY_2_3_NS = 5,
27 RGMII_RX_CLK_DELAY_2_6_NS = 6,
28 RGMII_RX_CLK_DELAY_3_4_NS = 7
Raju Lakkarajud50736a2016-08-05 17:54:21 +053029};
30
Raju Lakkaraju1a211012016-09-19 15:33:54 +053031/* Microsemi VSC85xx PHY registers */
32/* IEEE 802. Std Registers */
Raju Lakkaraju233275e2016-11-29 15:16:48 +053033#define MSCC_PHY_BYPASS_CONTROL 18
34#define DISABLE_HP_AUTO_MDIX_MASK 0x0080
35#define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
36#define DISABLE_POLARITY_CORR_MASK 0x0010
Quentin Schulza5afc162018-10-08 12:14:42 +020037#define PARALLEL_DET_IGNORE_ADVERTISED 0x0008
38
39#define MSCC_PHY_EXT_CNTL_STATUS 22
40#define SMI_BROADCAST_WR_EN 0x0001
Raju Lakkaraju233275e2016-11-29 15:16:48 +053041
Raju Lakkarajuf76178d2018-10-08 12:07:24 +020042#define MSCC_PHY_ERR_RX_CNT 19
43#define MSCC_PHY_ERR_FALSE_CARRIER_CNT 20
44#define MSCC_PHY_ERR_LINK_DISCONNECT_CNT 21
45#define ERR_CNT_MASK GENMASK(7, 0)
46
Raju Lakkaraju1a211012016-09-19 15:33:54 +053047#define MSCC_PHY_EXT_PHY_CNTL_1 23
48#define MAC_IF_SELECTION_MASK 0x1800
49#define MAC_IF_SELECTION_GMII 0
50#define MAC_IF_SELECTION_RMII 1
51#define MAC_IF_SELECTION_RGMII 2
52#define MAC_IF_SELECTION_POS 11
Quentin Schulza5afc162018-10-08 12:14:42 +020053#define VSC8584_MAC_IF_SELECTION_MASK 0x1000
54#define VSC8584_MAC_IF_SELECTION_SGMII 0
55#define VSC8584_MAC_IF_SELECTION_1000BASEX 1
56#define VSC8584_MAC_IF_SELECTION_POS 12
Raju Lakkaraju1a211012016-09-19 15:33:54 +053057#define FAR_END_LOOPBACK_MODE_MASK 0x0008
Quentin Schulza5afc162018-10-08 12:14:42 +020058#define MEDIA_OP_MODE_MASK 0x0700
59#define MEDIA_OP_MODE_COPPER 0
60#define MEDIA_OP_MODE_SERDES 1
61#define MEDIA_OP_MODE_1000BASEX 2
62#define MEDIA_OP_MODE_100BASEFX 3
63#define MEDIA_OP_MODE_AMS_COPPER_SERDES 5
64#define MEDIA_OP_MODE_AMS_COPPER_1000BASEX 6
65#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX 7
66#define MEDIA_OP_MODE_POS 8
Raju Lakkaraju1a211012016-09-19 15:33:54 +053067
Quentin Schulz00d70d82018-10-08 12:14:43 +020068#define MSCC_PHY_EXT_PHY_CNTL_2 24
69
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053070#define MII_VSC85XX_INT_MASK 25
71#define MII_VSC85XX_INT_MASK_MASK 0xa000
Raju Lakkaraju0a55c122016-10-05 14:19:27 +053072#define MII_VSC85XX_INT_MASK_WOL 0x0040
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053073#define MII_VSC85XX_INT_STATUS 26
Raju Lakkarajud50736a2016-08-05 17:54:21 +053074
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +053075#define MSCC_PHY_WOL_MAC_CONTROL 27
76#define EDGE_RATE_CNTL_POS 5
77#define EDGE_RATE_CNTL_MASK 0x00E0
78
Raju Lakkaraju233275e2016-11-29 15:16:48 +053079#define MSCC_PHY_DEV_AUX_CNTL 28
80#define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
81
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +053082#define MSCC_PHY_LED_MODE_SEL 29
Quentin Schulz11bfdab2018-09-03 10:48:47 +020083#define LED_MODE_SEL_POS(x) ((x) * 4)
84#define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
85#define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +053086
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053087#define MSCC_EXT_PAGE_ACCESS 31
88#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +010089#define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053090#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
Quentin Schulza5afc162018-10-08 12:14:42 +020091#define MSCC_PHY_PAGE_EXTENDED_3 0x0003 /* Extended reg - page 3 */
92#define MSCC_PHY_PAGE_EXTENDED_4 0x0004 /* Extended reg - page 4 */
93/* Extended reg - GPIO; this is a bank of registers that are shared for all PHYs
94 * in the same package.
95 */
96#define MSCC_PHY_PAGE_EXTENDED_GPIO 0x0010 /* Extended reg - GPIO */
97#define MSCC_PHY_PAGE_TEST 0x2a30 /* Test reg */
Raju Lakkaraju96dae012018-10-08 12:07:25 +020098#define MSCC_PHY_PAGE_TR 0x52b5 /* Token ring registers */
Raju Lakkarajud50736a2016-08-05 17:54:21 +053099
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100100/* Extended Page 1 Registers */
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200101#define MSCC_PHY_CU_MEDIA_CRC_VALID_CNT 18
102#define VALID_CRC_CNT_CRC_MASK GENMASK(13, 0)
103
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530104#define MSCC_PHY_EXT_MODE_CNTL 19
105#define FORCE_MDI_CROSSOVER_MASK 0x000C
106#define FORCE_MDI_CROSSOVER_MDIX 0x000C
107#define FORCE_MDI_CROSSOVER_MDI 0x0008
108
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100109#define MSCC_PHY_ACTIPHY_CNTL 20
Quentin Schulza5afc162018-10-08 12:14:42 +0200110#define PHY_ADDR_REVERSED 0x0200
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100111#define DOWNSHIFT_CNTL_MASK 0x001C
112#define DOWNSHIFT_EN 0x0010
113#define DOWNSHIFT_CNTL_POS 2
114
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200115#define MSCC_PHY_EXT_PHY_CNTL_4 23
Quentin Schulza5afc162018-10-08 12:14:42 +0200116#define PHY_CNTL_4_ADDR_POS 11
117
118#define MSCC_PHY_VERIPHY_CNTL_2 25
119
120#define MSCC_PHY_VERIPHY_CNTL_3 26
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200121
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530122/* Extended Page 2 Registers */
Quentin Schulza5afc162018-10-08 12:14:42 +0200123#define MSCC_PHY_CU_PMD_TX_CNTL 16
124
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530125#define MSCC_PHY_RGMII_CNTL 20
126#define RGMII_RX_CLK_DELAY_MASK 0x0070
127#define RGMII_RX_CLK_DELAY_POS 4
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530128
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530129#define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
130#define MSCC_PHY_WOL_MID_MAC_ADDR 22
131#define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
132#define MSCC_PHY_WOL_LOWER_PASSWD 24
133#define MSCC_PHY_WOL_MID_PASSWD 25
134#define MSCC_PHY_WOL_UPPER_PASSWD 26
135
136#define MSCC_PHY_WOL_MAC_CONTROL 27
137#define SECURE_ON_ENABLE 0x8000
138#define SECURE_ON_PASSWD_LEN_4 0x4000
139
Quentin Schulza5afc162018-10-08 12:14:42 +0200140/* Extended Page 3 Registers */
141#define MSCC_PHY_SERDES_TX_VALID_CNT 21
142#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22
143#define MSCC_PHY_SERDES_RX_VALID_CNT 28
144#define MSCC_PHY_SERDES_RX_CRC_ERR_CNT 29
145
146/* Extended page GPIO Registers */
147#define MSCC_DW8051_CNTL_STATUS 0
148#define MICRO_NSOFT_RESET 0x8000
149#define RUN_FROM_INT_ROM 0x4000
150#define AUTOINC_ADDR 0x2000
151#define PATCH_RAM_CLK 0x1000
152#define MICRO_PATCH_EN 0x0080
153#define DW8051_CLK_EN 0x0010
154#define MICRO_CLK_EN 0x0008
155#define MICRO_CLK_DIVIDE(x) ((x) >> 1)
Quentin Schulz00d70d82018-10-08 12:14:43 +0200156#define MSCC_DW8051_VLD_MASK 0xf1ff
Quentin Schulza5afc162018-10-08 12:14:42 +0200157
158/* x Address in range 1-4 */
159#define MSCC_TRAP_ROM_ADDR(x) ((x) * 2 + 1)
160#define MSCC_PATCH_RAM_ADDR(x) (((x) + 1) * 2)
161#define MSCC_INT_MEM_ADDR 11
162
163#define MSCC_INT_MEM_CNTL 12
164#define READ_SFR 0x6000
165#define READ_PRAM 0x4000
166#define READ_ROM 0x2000
167#define READ_RAM 0x0000
168#define INT_MEM_WRITE_EN 0x1000
169#define EN_PATCH_RAM_TRAP_ADDR(x) (0x0100 << ((x) - 1))
170#define INT_MEM_DATA_M 0x00ff
171#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
172
173#define MSCC_PHY_PROC_CMD 18
174#define PROC_CMD_NCOMPLETED 0x8000
175#define PROC_CMD_FAILED 0x4000
176#define PROC_CMD_SGMII_PORT(x) ((x) << 8)
177#define PROC_CMD_FIBER_PORT(x) (0x0100 << (x) % 4)
178#define PROC_CMD_QSGMII_PORT 0x0c00
179#define PROC_CMD_RST_CONF_PORT 0x0080
180#define PROC_CMD_RECONF_PORT 0x0000
181#define PROC_CMD_READ_MOD_WRITE_PORT 0x0040
182#define PROC_CMD_WRITE 0x0040
183#define PROC_CMD_READ 0x0000
184#define PROC_CMD_FIBER_DISABLE 0x0020
185#define PROC_CMD_FIBER_100BASE_FX 0x0010
186#define PROC_CMD_FIBER_1000BASE_X 0x0000
187#define PROC_CMD_SGMII_MAC 0x0030
188#define PROC_CMD_QSGMII_MAC 0x0020
189#define PROC_CMD_NO_MAC_CONF 0x0000
Quentin Schulz00d70d82018-10-08 12:14:43 +0200190#define PROC_CMD_1588_DEFAULT_INIT 0x0010
Quentin Schulza5afc162018-10-08 12:14:42 +0200191#define PROC_CMD_NOP 0x000f
Quentin Schulz00d70d82018-10-08 12:14:43 +0200192#define PROC_CMD_PHY_INIT 0x000a
Quentin Schulza5afc162018-10-08 12:14:42 +0200193#define PROC_CMD_CRC16 0x0008
194#define PROC_CMD_FIBER_MEDIA_CONF 0x0001
195#define PROC_CMD_MCB_ACCESS_MAC_CONF 0x0000
196#define PROC_CMD_NCOMPLETED_TIMEOUT_MS 500
197
198#define MSCC_PHY_MAC_CFG_FASTLINK 19
199#define MAC_CFG_MASK 0xc000
200#define MAC_CFG_SGMII 0x0000
201#define MAC_CFG_QSGMII 0x4000
202
203/* Test page Registers */
204#define MSCC_PHY_TEST_PAGE_5 5
205#define MSCC_PHY_TEST_PAGE_8 8
Quentin Schulz00d70d82018-10-08 12:14:43 +0200206#define MSCC_PHY_TEST_PAGE_9 9
207#define MSCC_PHY_TEST_PAGE_20 20
208#define MSCC_PHY_TEST_PAGE_24 24
Quentin Schulza5afc162018-10-08 12:14:42 +0200209
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200210/* Token ring page Registers */
211#define MSCC_PHY_TR_CNTL 16
212#define TR_WRITE 0x8000
213#define TR_ADDR(x) (0x7fff & (x))
214#define MSCC_PHY_TR_LSB 17
215#define MSCC_PHY_TR_MSB 18
216
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530217/* Microsemi PHY ID's */
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +0200218#define PHY_ID_VSC8530 0x00070560
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530219#define PHY_ID_VSC8531 0x00070570
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +0200220#define PHY_ID_VSC8540 0x00070760
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530221#define PHY_ID_VSC8541 0x00070770
Quentin Schulz00d70d82018-10-08 12:14:43 +0200222#define PHY_ID_VSC8574 0x000704a0
Quentin Schulza5afc162018-10-08 12:14:42 +0200223#define PHY_ID_VSC8584 0x000707c0
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530224
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200225#define MSCC_VDDMAC_1500 1500
226#define MSCC_VDDMAC_1800 1800
227#define MSCC_VDDMAC_2500 2500
228#define MSCC_VDDMAC_3300 3300
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530229
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100230#define DOWNSHIFT_COUNT_MAX 5
231
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200232#define MAX_LEDS 4
Quentin Schulza5afc162018-10-08 12:14:42 +0200233
234#define VSC8584_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
235 BIT(VSC8531_LINK_1000_ACTIVITY) | \
236 BIT(VSC8531_LINK_100_ACTIVITY) | \
237 BIT(VSC8531_LINK_10_ACTIVITY) | \
238 BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
239 BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
240 BIT(VSC8531_LINK_10_100_ACTIVITY) | \
241 BIT(VSC8584_LINK_100FX_1000X_ACTIVITY) | \
242 BIT(VSC8531_DUPLEX_COLLISION) | \
243 BIT(VSC8531_COLLISION) | \
244 BIT(VSC8531_ACTIVITY) | \
245 BIT(VSC8584_100FX_1000X_ACTIVITY) | \
246 BIT(VSC8531_AUTONEG_FAULT) | \
247 BIT(VSC8531_SERIAL_MODE) | \
248 BIT(VSC8531_FORCE_LED_OFF) | \
249 BIT(VSC8531_FORCE_LED_ON))
250
Quentin Schulz0969aba2018-09-03 10:48:48 +0200251#define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
252 BIT(VSC8531_LINK_1000_ACTIVITY) | \
253 BIT(VSC8531_LINK_100_ACTIVITY) | \
254 BIT(VSC8531_LINK_10_ACTIVITY) | \
255 BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
256 BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
257 BIT(VSC8531_LINK_10_100_ACTIVITY) | \
258 BIT(VSC8531_DUPLEX_COLLISION) | \
259 BIT(VSC8531_COLLISION) | \
260 BIT(VSC8531_ACTIVITY) | \
261 BIT(VSC8531_AUTONEG_FAULT) | \
262 BIT(VSC8531_SERIAL_MODE) | \
263 BIT(VSC8531_FORCE_LED_OFF) | \
264 BIT(VSC8531_FORCE_LED_ON))
265
Quentin Schulza5afc162018-10-08 12:14:42 +0200266#define MSCC_VSC8584_REVB_INT8051_FW "mscc_vsc8584_revb_int8051_fb48.bin"
267#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR 0xe800
268#define MSCC_VSC8584_REVB_INT8051_FW_CRC 0xfb48
269
Quentin Schulz00d70d82018-10-08 12:14:43 +0200270#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
Quentin Schulza5afc162018-10-08 12:14:42 +0200274#define VSC8584_REVB 0x0001
275#define MSCC_DEV_REV_MASK GENMASK(3, 0)
276
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200277struct reg_val {
278 u16 reg;
279 u32 val;
280};
281
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200282struct vsc85xx_hw_stat {
283 const char *string;
284 u8 reg;
285 u16 page;
286 u16 mask;
287};
288
289static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = {
290 {
291 .string = "phy_receive_errors",
292 .reg = MSCC_PHY_ERR_RX_CNT,
293 .page = MSCC_PHY_PAGE_STANDARD,
294 .mask = ERR_CNT_MASK,
295 }, {
296 .string = "phy_false_carrier",
297 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
298 .page = MSCC_PHY_PAGE_STANDARD,
299 .mask = ERR_CNT_MASK,
300 }, {
301 .string = "phy_cu_media_link_disconnect",
302 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
303 .page = MSCC_PHY_PAGE_STANDARD,
304 .mask = ERR_CNT_MASK,
305 }, {
306 .string = "phy_cu_media_crc_good_count",
307 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
308 .page = MSCC_PHY_PAGE_EXTENDED,
309 .mask = VALID_CRC_CNT_CRC_MASK,
310 }, {
311 .string = "phy_cu_media_crc_error_count",
312 .reg = MSCC_PHY_EXT_PHY_CNTL_4,
313 .page = MSCC_PHY_PAGE_EXTENDED,
314 .mask = ERR_CNT_MASK,
315 },
316};
317
Quentin Schulza5afc162018-10-08 12:14:42 +0200318static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
319 {
320 .string = "phy_receive_errors",
321 .reg = MSCC_PHY_ERR_RX_CNT,
322 .page = MSCC_PHY_PAGE_STANDARD,
323 .mask = ERR_CNT_MASK,
324 }, {
325 .string = "phy_false_carrier",
326 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
327 .page = MSCC_PHY_PAGE_STANDARD,
328 .mask = ERR_CNT_MASK,
329 }, {
330 .string = "phy_cu_media_link_disconnect",
331 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
332 .page = MSCC_PHY_PAGE_STANDARD,
333 .mask = ERR_CNT_MASK,
334 }, {
335 .string = "phy_cu_media_crc_good_count",
336 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
337 .page = MSCC_PHY_PAGE_EXTENDED,
338 .mask = VALID_CRC_CNT_CRC_MASK,
339 }, {
340 .string = "phy_cu_media_crc_error_count",
341 .reg = MSCC_PHY_EXT_PHY_CNTL_4,
342 .page = MSCC_PHY_PAGE_EXTENDED,
343 .mask = ERR_CNT_MASK,
344 }, {
345 .string = "phy_serdes_tx_good_pkt_count",
346 .reg = MSCC_PHY_SERDES_TX_VALID_CNT,
347 .page = MSCC_PHY_PAGE_EXTENDED_3,
348 .mask = VALID_CRC_CNT_CRC_MASK,
349 }, {
350 .string = "phy_serdes_tx_bad_crc_count",
351 .reg = MSCC_PHY_SERDES_TX_CRC_ERR_CNT,
352 .page = MSCC_PHY_PAGE_EXTENDED_3,
353 .mask = ERR_CNT_MASK,
354 }, {
355 .string = "phy_serdes_rx_good_pkt_count",
356 .reg = MSCC_PHY_SERDES_RX_VALID_CNT,
357 .page = MSCC_PHY_PAGE_EXTENDED_3,
358 .mask = VALID_CRC_CNT_CRC_MASK,
359 }, {
360 .string = "phy_serdes_rx_bad_crc_count",
361 .reg = MSCC_PHY_SERDES_RX_CRC_ERR_CNT,
362 .page = MSCC_PHY_PAGE_EXTENDED_3,
363 .mask = ERR_CNT_MASK,
364 },
365};
366
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530367struct vsc8531_private {
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200368 int rate_magic;
Quentin Schulz0969aba2018-09-03 10:48:48 +0200369 u16 supp_led_modes;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200370 u32 leds_mode[MAX_LEDS];
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200371 u8 nleds;
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200372 const struct vsc85xx_hw_stat *hw_stats;
373 u64 *stats;
374 int nstats;
Quentin Schulza5afc162018-10-08 12:14:42 +0200375 bool pkg_init;
376 /* For multiple port PHYs; the MDIO address of the base PHY in the
377 * package.
378 */
379 unsigned int base_addr;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530380};
381
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200382#ifdef CONFIG_OF_MDIO
383struct vsc8531_edge_rate_table {
Quentin Schulza993e0f2018-09-03 10:48:49 +0200384 u32 vddmac;
Quentin Schulz36c53cf2018-09-03 10:48:50 +0200385 u32 slowdown[8];
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200386};
387
388static const struct vsc8531_edge_rate_table edge_table[] = {
389 {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },
390 {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },
391 {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },
392 {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
393};
394#endif /* CONFIG_OF_MDIO */
395
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200396static int vsc85xx_phy_read_page(struct phy_device *phydev)
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530397{
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200398 return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);
399}
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530400
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200401static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
402{
403 return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530404}
405
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200406static int vsc85xx_get_sset_count(struct phy_device *phydev)
407{
408 struct vsc8531_private *priv = phydev->priv;
409
410 if (!priv)
411 return 0;
412
413 return priv->nstats;
414}
415
416static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)
417{
418 struct vsc8531_private *priv = phydev->priv;
419 int i;
420
421 if (!priv)
422 return;
423
424 for (i = 0; i < priv->nstats; i++)
425 strlcpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,
426 ETH_GSTRING_LEN);
427}
428
429static u64 vsc85xx_get_stat(struct phy_device *phydev, int i)
430{
431 struct vsc8531_private *priv = phydev->priv;
432 int val;
433
434 val = phy_read_paged(phydev, priv->hw_stats[i].page,
435 priv->hw_stats[i].reg);
436 if (val < 0)
437 return U64_MAX;
438
439 val = val & priv->hw_stats[i].mask;
440 priv->stats[i] += val;
441
442 return priv->stats[i];
443}
444
445static void vsc85xx_get_stats(struct phy_device *phydev,
446 struct ethtool_stats *stats, u64 *data)
447{
448 struct vsc8531_private *priv = phydev->priv;
449 int i;
450
451 if (!priv)
452 return;
453
454 for (i = 0; i < priv->nstats; i++)
455 data[i] = vsc85xx_get_stat(phydev, i);
456}
457
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530458static int vsc85xx_led_cntl_set(struct phy_device *phydev,
459 u8 led_num,
460 u8 mode)
461{
462 int rc;
463 u16 reg_val;
464
465 mutex_lock(&phydev->lock);
466 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200467 reg_val &= ~LED_MODE_SEL_MASK(led_num);
468 reg_val |= LED_MODE_SEL(led_num, (u16)mode);
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530469 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
470 mutex_unlock(&phydev->lock);
471
472 return rc;
473}
474
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530475static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
476{
477 u16 reg_val;
478
479 reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
480 if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
481 *mdix = ETH_TP_MDI_X;
482 else
483 *mdix = ETH_TP_MDI;
484
485 return 0;
486}
487
488static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
489{
490 int rc;
491 u16 reg_val;
492
493 reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
Quentin Schulzb7d373c2018-10-08 12:07:26 +0200494 if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) {
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530495 reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
496 DISABLE_POLARITY_CORR_MASK |
497 DISABLE_HP_AUTO_MDIX_MASK);
498 } else {
499 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
500 DISABLE_POLARITY_CORR_MASK |
501 DISABLE_HP_AUTO_MDIX_MASK);
502 }
503 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200504 if (rc)
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530505 return rc;
506
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200507 reg_val = 0;
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530508
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530509 if (mdix == ETH_TP_MDI)
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200510 reg_val = FORCE_MDI_CROSSOVER_MDI;
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530511 else if (mdix == ETH_TP_MDI_X)
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200512 reg_val = FORCE_MDI_CROSSOVER_MDIX;
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530513
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200514 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
515 MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,
516 reg_val);
517 if (rc < 0)
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530518 return rc;
519
520 return genphy_restart_aneg(phydev);
521}
522
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100523static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
524{
Gustavo A. R. Silvae5198692018-10-16 19:35:11 +0200525 int reg_val;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100526
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200527 reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
528 MSCC_PHY_ACTIPHY_CNTL);
529 if (reg_val < 0)
530 return reg_val;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100531
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100532 reg_val &= DOWNSHIFT_CNTL_MASK;
533 if (!(reg_val & DOWNSHIFT_EN))
534 *count = DOWNSHIFT_DEV_DISABLE;
535 else
536 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100537
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200538 return 0;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100539}
540
541static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
542{
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100543 if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
544 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
545 count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
546 } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
547 phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
548 return -ERANGE;
549 } else if (count) {
550 /* Downshift count is either 2,3,4 or 5 */
551 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
552 }
553
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200554 return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
555 MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,
556 count);
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100557}
558
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530559static int vsc85xx_wol_set(struct phy_device *phydev,
560 struct ethtool_wolinfo *wol)
561{
562 int rc;
563 u16 reg_val;
564 u8 i;
565 u16 pwd[3] = {0, 0, 0};
566 struct ethtool_wolinfo *wol_conf = wol;
567 u8 *mac_addr = phydev->attached_dev->dev_addr;
568
569 mutex_lock(&phydev->lock);
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200570 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
571 if (rc < 0) {
572 rc = phy_restore_page(phydev, rc, rc);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530573 goto out_unlock;
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200574 }
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530575
576 if (wol->wolopts & WAKE_MAGIC) {
577 /* Store the device address for the magic packet */
578 for (i = 0; i < ARRAY_SIZE(pwd); i++)
579 pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
580 mac_addr[5 - i * 2];
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200581 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
582 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
583 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530584 } else {
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200585 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
586 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
587 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530588 }
589
590 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
591 for (i = 0; i < ARRAY_SIZE(pwd); i++)
592 pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
593 wol_conf->sopass[5 - i * 2];
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200594 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
595 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
596 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530597 } else {
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200598 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
599 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
600 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530601 }
602
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200603 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530604 if (wol_conf->wolopts & WAKE_MAGICSECURE)
605 reg_val |= SECURE_ON_ENABLE;
606 else
607 reg_val &= ~SECURE_ON_ENABLE;
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200608 __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530609
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200610 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
611 if (rc < 0)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530612 goto out_unlock;
613
614 if (wol->wolopts & WAKE_MAGIC) {
615 /* Enable the WOL interrupt */
616 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
617 reg_val |= MII_VSC85XX_INT_MASK_WOL;
618 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200619 if (rc)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530620 goto out_unlock;
621 } else {
622 /* Disable the WOL interrupt */
623 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
624 reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
625 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200626 if (rc)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530627 goto out_unlock;
628 }
629 /* Clear WOL iterrupt status */
630 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
631
632out_unlock:
633 mutex_unlock(&phydev->lock);
634
635 return rc;
636}
637
638static void vsc85xx_wol_get(struct phy_device *phydev,
639 struct ethtool_wolinfo *wol)
640{
641 int rc;
642 u16 reg_val;
643 u8 i;
644 u16 pwd[3] = {0, 0, 0};
645 struct ethtool_wolinfo *wol_conf = wol;
646
647 mutex_lock(&phydev->lock);
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200648 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
649 if (rc < 0)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530650 goto out_unlock;
651
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200652 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530653 if (reg_val & SECURE_ON_ENABLE)
654 wol_conf->wolopts |= WAKE_MAGICSECURE;
655 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200656 pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
657 pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
658 pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530659 for (i = 0; i < ARRAY_SIZE(pwd); i++) {
660 wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
661 wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
662 >> 8;
663 }
664 }
665
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530666out_unlock:
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200667 phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530668 mutex_unlock(&phydev->lock);
669}
670
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200671#ifdef CONFIG_OF_MDIO
672static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530673{
Quentin Schulz36c53cf2018-09-03 10:48:50 +0200674 u32 vdd, sd;
Quentin Schulz629ea0f2018-10-08 12:07:28 +0200675 int i, j;
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200676 struct device *dev = &phydev->mdio.dev;
677 struct device_node *of_node = dev->of_node;
678 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530679
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200680 if (!of_node)
681 return -ENODEV;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530682
Quentin Schulz629ea0f2018-10-08 12:07:28 +0200683 if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd))
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200684 vdd = MSCC_VDDMAC_3300;
685
Quentin Schulz629ea0f2018-10-08 12:07:28 +0200686 if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd))
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200687 sd = 0;
688
689 for (i = 0; i < ARRAY_SIZE(edge_table); i++)
690 if (edge_table[i].vddmac == vdd)
691 for (j = 0; j < sd_array_size; j++)
692 if (edge_table[i].slowdown[j] == sd)
693 return (sd_array_size - j - 1);
694
695 return -EINVAL;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530696}
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530697
698static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
699 char *led,
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200700 u32 default_mode)
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530701{
Quentin Schulz0969aba2018-09-03 10:48:48 +0200702 struct vsc8531_private *priv = phydev->priv;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530703 struct device *dev = &phydev->mdio.dev;
704 struct device_node *of_node = dev->of_node;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200705 u32 led_mode;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530706 int err;
707
708 if (!of_node)
709 return -ENODEV;
710
711 led_mode = default_mode;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200712 err = of_property_read_u32(of_node, led, &led_mode);
Quentin Schulz0969aba2018-09-03 10:48:48 +0200713 if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530714 phydev_err(phydev, "DT %s invalid\n", led);
715 return -EINVAL;
716 }
717
718 return led_mode;
719}
720
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200721#else
722static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
723{
724 return 0;
725}
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530726
727static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
728 char *led,
729 u8 default_mode)
730{
731 return default_mode;
732}
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200733#endif /* CONFIG_OF_MDIO */
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530734
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200735static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
736 u32 *default_mode)
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200737{
738 struct vsc8531_private *priv = phydev->priv;
Arnd Bergmann31bae7d2018-09-26 15:20:11 +0200739 char led_dt_prop[28];
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200740 int i, ret;
741
742 for (i = 0; i < priv->nleds; i++) {
743 ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
744 if (ret < 0)
745 return ret;
746
747 ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,
748 default_mode[i]);
749 if (ret < 0)
750 return ret;
751 priv->leds_mode[i] = ret;
752 }
753
754 return 0;
755}
756
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200757static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530758{
759 int rc;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530760
761 mutex_lock(&phydev->lock);
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200762 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
763 MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,
764 edge_rate << EDGE_RATE_CNTL_POS);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530765 mutex_unlock(&phydev->lock);
766
767 return rc;
768}
769
Raju Lakkaraju1a211012016-09-19 15:33:54 +0530770static int vsc85xx_mac_if_set(struct phy_device *phydev,
771 phy_interface_t interface)
772{
773 int rc;
774 u16 reg_val;
775
776 mutex_lock(&phydev->lock);
777 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
778 reg_val &= ~(MAC_IF_SELECTION_MASK);
779 switch (interface) {
780 case PHY_INTERFACE_MODE_RGMII:
781 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
782 break;
783 case PHY_INTERFACE_MODE_RMII:
784 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
785 break;
786 case PHY_INTERFACE_MODE_MII:
787 case PHY_INTERFACE_MODE_GMII:
788 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
789 break;
790 default:
791 rc = -EINVAL;
792 goto out_unlock;
793 }
794 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200795 if (rc)
Raju Lakkaraju1a211012016-09-19 15:33:54 +0530796 goto out_unlock;
797
798 rc = genphy_soft_reset(phydev);
799
800out_unlock:
801 mutex_unlock(&phydev->lock);
802
803 return rc;
804}
805
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530806static int vsc85xx_default_config(struct phy_device *phydev)
807{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530808 int rc;
809 u16 reg_val;
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530810
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530811 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530812 mutex_lock(&phydev->lock);
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530813
Quentin Schulz3fa528b2018-11-23 19:01:51 +0100814 reg_val = RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS;
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530815
Quentin Schulz3fa528b2018-11-23 19:01:51 +0100816 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
817 MSCC_PHY_RGMII_CNTL, RGMII_RX_CLK_DELAY_MASK,
818 reg_val);
819
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530820 mutex_unlock(&phydev->lock);
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530821
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530822 return rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530823}
824
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100825static int vsc85xx_get_tunable(struct phy_device *phydev,
826 struct ethtool_tunable *tuna, void *data)
827{
828 switch (tuna->id) {
829 case ETHTOOL_PHY_DOWNSHIFT:
830 return vsc85xx_downshift_get(phydev, (u8 *)data);
831 default:
832 return -EINVAL;
833 }
834}
835
836static int vsc85xx_set_tunable(struct phy_device *phydev,
837 struct ethtool_tunable *tuna,
838 const void *data)
839{
840 switch (tuna->id) {
841 case ETHTOOL_PHY_DOWNSHIFT:
842 return vsc85xx_downshift_set(phydev, *(u8 *)data);
843 default:
844 return -EINVAL;
845 }
846}
847
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200848/* mdiobus lock should be locked when using this function */
849static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val)
850{
851 __phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
852 __phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
853 __phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
854}
855
Raju Lakkaraju7b98f632018-12-18 14:57:56 +0530856static int vsc8531_pre_init_seq_set(struct phy_device *phydev)
857{
858 int rc;
859 const struct reg_val init_seq[] = {
860 {0x0f90, 0x00688980},
861 {0x0696, 0x00000003},
862 {0x07fa, 0x0050100f},
863 {0x1686, 0x00000004},
864 };
865 unsigned int i;
866 int oldpage;
867
868 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_STANDARD,
869 MSCC_PHY_EXT_CNTL_STATUS, SMI_BROADCAST_WR_EN,
870 SMI_BROADCAST_WR_EN);
871 if (rc < 0)
872 return rc;
873 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
874 MSCC_PHY_TEST_PAGE_24, 0, 0x0400);
875 if (rc < 0)
876 return rc;
877 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
878 MSCC_PHY_TEST_PAGE_5, 0x0a00, 0x0e00);
879 if (rc < 0)
880 return rc;
881 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
882 MSCC_PHY_TEST_PAGE_8, 0x8000, 0x8000);
883 if (rc < 0)
884 return rc;
885
886 mutex_lock(&phydev->lock);
887 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
888 if (oldpage < 0)
889 goto out_unlock;
890
891 for (i = 0; i < ARRAY_SIZE(init_seq); i++)
892 vsc85xx_tr_write(phydev, init_seq[i].reg, init_seq[i].val);
893
894out_unlock:
895 oldpage = phy_restore_page(phydev, oldpage, oldpage);
896 mutex_unlock(&phydev->lock);
897
898 return oldpage;
899}
900
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200901static int vsc85xx_eee_init_seq_set(struct phy_device *phydev)
902{
903 const struct reg_val init_eee[] = {
904 {0x0f82, 0x0012b00a},
905 {0x1686, 0x00000004},
906 {0x168c, 0x00d2c46f},
907 {0x17a2, 0x00000620},
908 {0x16a0, 0x00eeffdd},
909 {0x16a6, 0x00071448},
910 {0x16a4, 0x0013132f},
911 {0x16a8, 0x00000000},
912 {0x0ffc, 0x00c0a028},
913 {0x0fe8, 0x0091b06c},
914 {0x0fea, 0x00041600},
915 {0x0f80, 0x00000af4},
916 {0x0fec, 0x00901809},
917 {0x0fee, 0x0000a6a1},
918 {0x0ffe, 0x00b01007},
919 {0x16b0, 0x00eeff00},
920 {0x16b2, 0x00007000},
921 {0x16b4, 0x00000814},
922 };
923 unsigned int i;
924 int oldpage;
925
926 mutex_lock(&phydev->lock);
927 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
928 if (oldpage < 0)
929 goto out_unlock;
930
931 for (i = 0; i < ARRAY_SIZE(init_eee); i++)
932 vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);
933
934out_unlock:
935 oldpage = phy_restore_page(phydev, oldpage, oldpage);
936 mutex_unlock(&phydev->lock);
937
938 return oldpage;
939}
940
Quentin Schulza5afc162018-10-08 12:14:42 +0200941/* phydev->bus->mdio_lock should be locked when using this function */
942static int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
943{
944 struct vsc8531_private *priv = phydev->priv;
945
946 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
947 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
948 dump_stack();
949 }
950
951 return __mdiobus_write(phydev->mdio.bus, priv->base_addr, regnum, val);
952}
953
954/* phydev->bus->mdio_lock should be locked when using this function */
955static int phy_base_read(struct phy_device *phydev, u32 regnum)
956{
957 struct vsc8531_private *priv = phydev->priv;
958
959 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
960 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
961 dump_stack();
962 }
963
964 return __mdiobus_read(phydev->mdio.bus, priv->base_addr, regnum);
965}
966
967/* bus->mdio_lock should be locked when using this function */
968static void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val)
969{
970 phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
971 phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
972 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
973}
974
975/* bus->mdio_lock should be locked when using this function */
976static int vsc8584_cmd(struct phy_device *phydev, u16 val)
977{
978 unsigned long deadline;
979 u16 reg_val;
980
981 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
982 MSCC_PHY_PAGE_EXTENDED_GPIO);
983
984 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val);
985
986 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
987 do {
988 reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD);
989 } while (time_before(jiffies, deadline) &&
990 (reg_val & PROC_CMD_NCOMPLETED) &&
991 !(reg_val & PROC_CMD_FAILED));
992
993 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
994
995 if (reg_val & PROC_CMD_FAILED)
996 return -EIO;
997
998 if (reg_val & PROC_CMD_NCOMPLETED)
999 return -ETIMEDOUT;
1000
1001 return 0;
1002}
1003
1004/* bus->mdio_lock should be locked when using this function */
1005static int vsc8584_micro_deassert_reset(struct phy_device *phydev,
1006 bool patch_en)
1007{
1008 u32 enable, release;
1009
1010 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1011 MSCC_PHY_PAGE_EXTENDED_GPIO);
1012
1013 enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
1014 release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
1015 MICRO_CLK_EN;
1016
1017 if (patch_en) {
1018 enable |= MICRO_PATCH_EN;
1019 release |= MICRO_PATCH_EN;
1020
1021 /* Clear all patches */
1022 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
1023 }
1024
1025 /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock
1026 * override and addr. auto-incr; operate at 125 MHz
1027 */
1028 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable);
1029 /* Release 8051 Micro SW reset */
1030 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release);
1031
1032 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1033
1034 return 0;
1035}
1036
1037/* bus->mdio_lock should be locked when using this function */
1038static int vsc8584_micro_assert_reset(struct phy_device *phydev)
1039{
1040 int ret;
1041 u16 reg;
1042
1043 ret = vsc8584_cmd(phydev, PROC_CMD_NOP);
1044 if (ret)
1045 return ret;
1046
1047 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1048 MSCC_PHY_PAGE_EXTENDED_GPIO);
1049
1050 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1051 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
1052 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1053
1054 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b);
1055 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b);
1056
1057 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1058 reg |= EN_PATCH_RAM_TRAP_ADDR(4);
1059 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1060
1061 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
1062
1063 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
1064 reg &= ~MICRO_NSOFT_RESET;
1065 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg);
1066
1067 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF |
1068 PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF |
1069 PROC_CMD_READ);
1070
1071 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1072 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
1073 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1074
1075 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1076
1077 return 0;
1078}
1079
1080/* bus->mdio_lock should be locked when using this function */
1081static int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size,
1082 u16 *crc)
1083{
1084 int ret;
1085
1086 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1087
1088 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start);
1089 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size);
1090
1091 /* Start Micro command */
1092 ret = vsc8584_cmd(phydev, PROC_CMD_CRC16);
1093 if (ret)
1094 goto out;
1095
1096 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1097
1098 *crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
1099
1100out:
1101 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1102
1103 return ret;
1104}
1105
1106/* bus->mdio_lock should be locked when using this function */
1107static int vsc8584_patch_fw(struct phy_device *phydev,
1108 const struct firmware *fw)
1109{
1110 int i, ret;
1111
1112 ret = vsc8584_micro_assert_reset(phydev);
1113 if (ret) {
1114 dev_err(&phydev->mdio.dev,
1115 "%s: failed to assert reset of micro\n", __func__);
1116 return ret;
1117 }
1118
1119 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1120 MSCC_PHY_PAGE_EXTENDED_GPIO);
1121
1122 /* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
1123 * Disable the 8051 Micro clock
1124 */
1125 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM |
1126 AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN |
1127 MICRO_CLK_DIVIDE(2));
1128 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN |
1129 INT_MEM_DATA(2));
1130 phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000);
1131
1132 for (i = 0; i < fw->size; i++)
1133 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM |
1134 INT_MEM_WRITE_EN | fw->data[i]);
1135
1136 /* Clear internal memory access */
1137 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
1138
1139 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1140
1141 return 0;
1142}
1143
1144/* bus->mdio_lock should be locked when using this function */
Quentin Schulz00d70d82018-10-08 12:14:43 +02001145static bool vsc8574_is_serdes_init(struct phy_device *phydev)
1146{
1147 u16 reg;
1148 bool ret;
1149
1150 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1151 MSCC_PHY_PAGE_EXTENDED_GPIO);
1152
1153 reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));
1154 if (reg != 0x3eb7) {
1155 ret = false;
1156 goto out;
1157 }
1158
1159 reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));
1160 if (reg != 0x4012) {
1161 ret = false;
1162 goto out;
1163 }
1164
1165 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1166 if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
1167 ret = false;
1168 goto out;
1169 }
1170
1171 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
1172 if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
1173 MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
1174 ret = false;
1175 goto out;
1176 }
1177
1178 ret = true;
1179out:
1180 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1181
1182 return ret;
1183}
1184
1185/* bus->mdio_lock should be locked when using this function */
1186static int vsc8574_config_pre_init(struct phy_device *phydev)
1187{
1188 const struct reg_val pre_init1[] = {
1189 {0x0fae, 0x000401bd},
1190 {0x0fac, 0x000f000f},
1191 {0x17a0, 0x00a0f147},
1192 {0x0fe4, 0x00052f54},
1193 {0x1792, 0x0027303d},
1194 {0x07fe, 0x00000704},
1195 {0x0fe0, 0x00060150},
1196 {0x0f82, 0x0012b00a},
1197 {0x0f80, 0x00000d74},
1198 {0x02e0, 0x00000012},
1199 {0x03a2, 0x00050208},
1200 {0x03b2, 0x00009186},
1201 {0x0fb0, 0x000e3700},
1202 {0x1688, 0x00049f81},
1203 {0x0fd2, 0x0000ffff},
1204 {0x168a, 0x00039fa2},
1205 {0x1690, 0x0020640b},
1206 {0x0258, 0x00002220},
1207 {0x025a, 0x00002a20},
1208 {0x025c, 0x00003060},
1209 {0x025e, 0x00003fa0},
1210 {0x03a6, 0x0000e0f0},
1211 {0x0f92, 0x00001489},
1212 {0x16a2, 0x00007000},
1213 {0x16a6, 0x00071448},
1214 {0x16a0, 0x00eeffdd},
1215 {0x0fe8, 0x0091b06c},
1216 {0x0fea, 0x00041600},
1217 {0x16b0, 0x00eeff00},
1218 {0x16b2, 0x00007000},
1219 {0x16b4, 0x00000814},
1220 {0x0f90, 0x00688980},
1221 {0x03a4, 0x0000d8f0},
1222 {0x0fc0, 0x00000400},
1223 {0x07fa, 0x0050100f},
1224 {0x0796, 0x00000003},
1225 {0x07f8, 0x00c3ff98},
1226 {0x0fa4, 0x0018292a},
1227 {0x168c, 0x00d2c46f},
1228 {0x17a2, 0x00000620},
1229 {0x16a4, 0x0013132f},
1230 {0x16a8, 0x00000000},
1231 {0x0ffc, 0x00c0a028},
1232 {0x0fec, 0x00901c09},
1233 {0x0fee, 0x0004a6a1},
1234 {0x0ffe, 0x00b01807},
1235 };
1236 const struct reg_val pre_init2[] = {
1237 {0x0486, 0x0008a518},
1238 {0x0488, 0x006dc696},
1239 {0x048a, 0x00000912},
1240 {0x048e, 0x00000db6},
1241 {0x049c, 0x00596596},
1242 {0x049e, 0x00000514},
1243 {0x04a2, 0x00410280},
1244 {0x04a4, 0x00000000},
1245 {0x04a6, 0x00000000},
1246 {0x04a8, 0x00000000},
1247 {0x04aa, 0x00000000},
1248 {0x04ae, 0x007df7dd},
1249 {0x04b0, 0x006d95d4},
1250 {0x04b2, 0x00492410},
1251 };
1252 struct device *dev = &phydev->mdio.dev;
1253 const struct firmware *fw;
1254 unsigned int i;
1255 u16 crc, reg;
1256 bool serdes_init;
1257 int ret;
1258
1259 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1260
1261 /* all writes below are broadcasted to all PHYs in the same package */
1262 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1263 reg |= SMI_BROADCAST_WR_EN;
1264 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1265
1266 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
1267
1268 /* The below register writes are tweaking analog and electrical
1269 * configuration that were determined through characterization by PHY
1270 * engineers. These don't mean anything more than "these are the best
1271 * values".
1272 */
1273 phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
1274
1275 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1276
1277 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);
1278 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);
1279 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);
1280 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);
1281
1282 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1283 reg |= 0x8000;
1284 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1285
1286 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1287
1288 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1289 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1290
1291 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1292
1293 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
1294
1295 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1296
1297 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
1298 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
1299
1300 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1301
1302 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1303 reg &= ~0x8000;
1304 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1305
1306 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1307
1308 /* end of write broadcasting */
1309 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1310 reg &= ~SMI_BROADCAST_WR_EN;
1311 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1312
1313 ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);
1314 if (ret) {
1315 dev_err(dev, "failed to load firmware %s, ret: %d\n",
1316 MSCC_VSC8574_REVB_INT8051_FW, ret);
1317 return ret;
1318 }
1319
1320 /* Add one byte to size for the one added by the patch_fw function */
1321 ret = vsc8584_get_fw_crc(phydev,
1322 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
1323 fw->size + 1, &crc);
1324 if (ret)
1325 goto out;
1326
1327 if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
1328 serdes_init = vsc8574_is_serdes_init(phydev);
1329
1330 if (!serdes_init) {
1331 ret = vsc8584_micro_assert_reset(phydev);
1332 if (ret) {
1333 dev_err(dev,
1334 "%s: failed to assert reset of micro\n",
1335 __func__);
Gustavo A. R. Silva47d20212018-10-16 19:37:35 +02001336 goto out;
Quentin Schulz00d70d82018-10-08 12:14:43 +02001337 }
1338 }
1339 } else {
1340 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
1341
1342 serdes_init = false;
1343
1344 if (vsc8584_patch_fw(phydev, fw))
1345 dev_warn(dev,
1346 "failed to patch FW, expect non-optimal device\n");
1347 }
1348
1349 if (!serdes_init) {
1350 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1351 MSCC_PHY_PAGE_EXTENDED_GPIO);
1352
1353 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);
1354 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);
1355 phy_base_write(phydev, MSCC_INT_MEM_CNTL,
1356 EN_PATCH_RAM_TRAP_ADDR(1));
1357
1358 vsc8584_micro_deassert_reset(phydev, false);
1359
1360 /* Add one byte to size for the one added by the patch_fw
1361 * function
1362 */
1363 ret = vsc8584_get_fw_crc(phydev,
1364 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
1365 fw->size + 1, &crc);
1366 if (ret)
1367 goto out;
1368
1369 if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
1370 dev_warn(dev,
1371 "FW CRC after patching is not the expected one, expect non-optimal device\n");
1372 }
1373
1374 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1375 MSCC_PHY_PAGE_EXTENDED_GPIO);
1376
1377 ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |
1378 PROC_CMD_PHY_INIT);
1379
1380out:
1381 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1382
1383 release_firmware(fw);
1384
1385 return ret;
1386}
1387
1388/* bus->mdio_lock should be locked when using this function */
Quentin Schulza5afc162018-10-08 12:14:42 +02001389static int vsc8584_config_pre_init(struct phy_device *phydev)
1390{
1391 const struct reg_val pre_init1[] = {
1392 {0x07fa, 0x0050100f},
1393 {0x1688, 0x00049f81},
1394 {0x0f90, 0x00688980},
1395 {0x03a4, 0x0000d8f0},
1396 {0x0fc0, 0x00000400},
1397 {0x0f82, 0x0012b002},
1398 {0x1686, 0x00000004},
1399 {0x168c, 0x00d2c46f},
1400 {0x17a2, 0x00000620},
1401 {0x16a0, 0x00eeffdd},
1402 {0x16a6, 0x00071448},
1403 {0x16a4, 0x0013132f},
1404 {0x16a8, 0x00000000},
1405 {0x0ffc, 0x00c0a028},
1406 {0x0fe8, 0x0091b06c},
1407 {0x0fea, 0x00041600},
1408 {0x0f80, 0x00fffaff},
1409 {0x0fec, 0x00901809},
1410 {0x0ffe, 0x00b01007},
1411 {0x16b0, 0x00eeff00},
1412 {0x16b2, 0x00007000},
1413 {0x16b4, 0x00000814},
1414 };
1415 const struct reg_val pre_init2[] = {
1416 {0x0486, 0x0008a518},
1417 {0x0488, 0x006dc696},
1418 {0x048a, 0x00000912},
1419 };
1420 const struct firmware *fw;
1421 struct device *dev = &phydev->mdio.dev;
1422 unsigned int i;
1423 u16 crc, reg;
1424 int ret;
1425
1426 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1427
1428 /* all writes below are broadcasted to all PHYs in the same package */
1429 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1430 reg |= SMI_BROADCAST_WR_EN;
1431 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1432
1433 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
1434
1435 reg = phy_base_read(phydev, MSCC_PHY_BYPASS_CONTROL);
1436 reg |= PARALLEL_DET_IGNORE_ADVERTISED;
1437 phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg);
1438
1439 /* The below register writes are tweaking analog and electrical
1440 * configuration that were determined through characterization by PHY
1441 * engineers. These don't mean anything more than "these are the best
1442 * values".
1443 */
1444 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
1445
1446 phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000);
1447
1448 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1449
1450 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20);
1451
1452 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1453 reg |= 0x8000;
1454 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1455
1456 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1457
1458 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4));
1459
1460 reg = phy_base_read(phydev, MSCC_PHY_TR_MSB);
1461 reg &= ~0x007f;
1462 reg |= 0x0019;
1463 phy_base_write(phydev, MSCC_PHY_TR_MSB, reg);
1464
1465 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4));
1466
1467 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1468 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1469
1470 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1471
1472 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
1473
1474 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1475
1476 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
1477 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
1478
1479 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1480
1481 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1482 reg &= ~0x8000;
1483 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1484
1485 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1486
1487 /* end of write broadcasting */
1488 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1489 reg &= ~SMI_BROADCAST_WR_EN;
1490 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1491
1492 ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev);
1493 if (ret) {
1494 dev_err(dev, "failed to load firmware %s, ret: %d\n",
1495 MSCC_VSC8584_REVB_INT8051_FW, ret);
1496 return ret;
1497 }
1498
1499 /* Add one byte to size for the one added by the patch_fw function */
1500 ret = vsc8584_get_fw_crc(phydev,
1501 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
1502 fw->size + 1, &crc);
1503 if (ret)
1504 goto out;
1505
1506 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
1507 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
1508 if (vsc8584_patch_fw(phydev, fw))
1509 dev_warn(dev,
1510 "failed to patch FW, expect non-optimal device\n");
1511 }
1512
1513 vsc8584_micro_deassert_reset(phydev, false);
1514
1515 /* Add one byte to size for the one added by the patch_fw function */
1516 ret = vsc8584_get_fw_crc(phydev,
1517 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
1518 fw->size + 1, &crc);
1519 if (ret)
1520 goto out;
1521
1522 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
1523 dev_warn(dev,
1524 "FW CRC after patching is not the expected one, expect non-optimal device\n");
1525
1526 ret = vsc8584_micro_assert_reset(phydev);
1527 if (ret)
1528 goto out;
1529
1530 vsc8584_micro_deassert_reset(phydev, true);
1531
1532out:
1533 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1534
1535 release_firmware(fw);
1536
1537 return ret;
1538}
1539
1540/* Check if one PHY has already done the init of the parts common to all PHYs
1541 * in the Quad PHY package.
1542 */
1543static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed)
1544{
1545 struct mdio_device **map = phydev->mdio.bus->mdio_map;
1546 struct vsc8531_private *vsc8531;
1547 struct phy_device *phy;
1548 int i, addr;
1549
1550 /* VSC8584 is a Quad PHY */
1551 for (i = 0; i < 4; i++) {
1552 vsc8531 = phydev->priv;
1553
1554 if (reversed)
1555 addr = vsc8531->base_addr - i;
1556 else
1557 addr = vsc8531->base_addr + i;
1558
1559 phy = container_of(map[addr], struct phy_device, mdio);
1560
1561 if ((phy->phy_id & phydev->drv->phy_id_mask) !=
1562 (phydev->drv->phy_id & phydev->drv->phy_id_mask))
1563 continue;
1564
1565 vsc8531 = phy->priv;
1566
1567 if (vsc8531 && vsc8531->pkg_init)
1568 return true;
1569 }
1570
1571 return false;
1572}
1573
1574static int vsc8584_config_init(struct phy_device *phydev)
1575{
1576 struct vsc8531_private *vsc8531 = phydev->priv;
1577 u16 addr, val;
1578 int ret, i;
1579
1580 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1581
1582 mutex_lock(&phydev->mdio.bus->mdio_lock);
1583
1584 __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
1585 MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1586 addr = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
1587 MSCC_PHY_EXT_PHY_CNTL_4);
1588 addr >>= PHY_CNTL_4_ADDR_POS;
1589
1590 val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
1591 MSCC_PHY_ACTIPHY_CNTL);
1592 if (val & PHY_ADDR_REVERSED)
1593 vsc8531->base_addr = phydev->mdio.addr + addr;
1594 else
1595 vsc8531->base_addr = phydev->mdio.addr - addr;
1596
1597 /* Some parts of the init sequence are identical for every PHY in the
1598 * package. Some parts are modifying the GPIO register bank which is a
1599 * set of registers that are affecting all PHYs, a few resetting the
1600 * microprocessor common to all PHYs. The CRC check responsible of the
1601 * checking the firmware within the 8051 microprocessor can only be
1602 * accessed via the PHY whose internal address in the package is 0.
1603 * All PHYs' interrupts mask register has to be zeroed before enabling
1604 * any PHY's interrupt in this register.
1605 * For all these reasons, we need to do the init sequence once and only
1606 * once whatever is the first PHY in the package that is initialized and
1607 * do the correct init sequence for all PHYs that are package-critical
1608 * in this pre-init function.
1609 */
1610 if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
Quentin Schulz00d70d82018-10-08 12:14:43 +02001611 if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
1612 (PHY_ID_VSC8574 & phydev->drv->phy_id_mask))
1613 ret = vsc8574_config_pre_init(phydev);
1614 else if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
1615 (PHY_ID_VSC8584 & phydev->drv->phy_id_mask))
1616 ret = vsc8584_config_pre_init(phydev);
1617 else
1618 ret = -EINVAL;
1619
Quentin Schulza5afc162018-10-08 12:14:42 +02001620 if (ret)
1621 goto err;
1622 }
1623
1624 vsc8531->pkg_init = true;
1625
1626 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1627 MSCC_PHY_PAGE_EXTENDED_GPIO);
1628
1629 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
1630 val &= ~MAC_CFG_MASK;
1631 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1632 val |= MAC_CFG_QSGMII;
1633 else
1634 val |= MAC_CFG_SGMII;
1635
1636 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
1637 if (ret)
1638 goto err;
1639
1640 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
1641 PROC_CMD_READ_MOD_WRITE_PORT;
1642 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1643 val |= PROC_CMD_QSGMII_MAC;
1644 else
1645 val |= PROC_CMD_SGMII_MAC;
1646
1647 ret = vsc8584_cmd(phydev, val);
1648 if (ret)
1649 goto err;
1650
1651 usleep_range(10000, 20000);
1652
1653 /* Disable SerDes for 100Base-FX */
1654 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
1655 PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1656 PROC_CMD_READ_MOD_WRITE_PORT |
1657 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
1658 if (ret)
1659 goto err;
1660
1661 /* Disable SerDes for 1000Base-X */
1662 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
1663 PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1664 PROC_CMD_READ_MOD_WRITE_PORT |
1665 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
1666 if (ret)
1667 goto err;
1668
1669 mutex_unlock(&phydev->mdio.bus->mdio_lock);
1670
1671 phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1672
1673 val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
1674 val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
1675 val |= MEDIA_OP_MODE_COPPER | (VSC8584_MAC_IF_SELECTION_SGMII <<
1676 VSC8584_MAC_IF_SELECTION_POS);
1677 ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);
1678
1679 ret = genphy_soft_reset(phydev);
1680 if (ret)
1681 return ret;
1682
1683 for (i = 0; i < vsc8531->nleds; i++) {
1684 ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
1685 if (ret)
1686 return ret;
1687 }
1688
1689 return genphy_config_init(phydev);
1690
1691err:
1692 mutex_unlock(&phydev->mdio.bus->mdio_lock);
1693 return ret;
1694}
1695
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301696static int vsc85xx_config_init(struct phy_device *phydev)
1697{
Raju Lakkaraju7b98f632018-12-18 14:57:56 +05301698 int rc, i, phy_id;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301699 struct vsc8531_private *vsc8531 = phydev->priv;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301700
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301701 rc = vsc85xx_default_config(phydev);
1702 if (rc)
1703 return rc;
Raju Lakkaraju1a211012016-09-19 15:33:54 +05301704
1705 rc = vsc85xx_mac_if_set(phydev, phydev->interface);
1706 if (rc)
1707 return rc;
1708
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001709 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301710 if (rc)
1711 return rc;
1712
Raju Lakkaraju7b98f632018-12-18 14:57:56 +05301713 phy_id = phydev->drv->phy_id & phydev->drv->phy_id_mask;
1714 if (PHY_ID_VSC8531 == phy_id || PHY_ID_VSC8541 == phy_id ||
1715 PHY_ID_VSC8530 == phy_id || PHY_ID_VSC8540 == phy_id) {
1716 rc = vsc8531_pre_init_seq_set(phydev);
1717 if (rc)
1718 return rc;
1719 }
1720
Raju Lakkaraju96dae012018-10-08 12:07:25 +02001721 rc = vsc85xx_eee_init_seq_set(phydev);
1722 if (rc)
1723 return rc;
1724
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001725 for (i = 0; i < vsc8531->nleds; i++) {
1726 rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
1727 if (rc)
1728 return rc;
1729 }
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +05301730
Quentin Schulz629ea0f2018-10-08 12:07:28 +02001731 return genphy_config_init(phydev);
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301732}
1733
Quentin Schulza5afc162018-10-08 12:14:42 +02001734static int vsc8584_did_interrupt(struct phy_device *phydev)
1735{
1736 int rc = 0;
1737
1738 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
1739 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
1740
1741 return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
1742}
1743
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301744static int vsc85xx_ack_interrupt(struct phy_device *phydev)
1745{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301746 int rc = 0;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301747
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301748 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
1749 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301750
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301751 return (rc < 0) ? rc : 0;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301752}
1753
1754static int vsc85xx_config_intr(struct phy_device *phydev)
1755{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301756 int rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301757
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301758 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1759 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
1760 MII_VSC85XX_INT_MASK_MASK);
1761 } else {
1762 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
1763 if (rc < 0)
1764 return rc;
1765 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
1766 }
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301767
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301768 return rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301769}
1770
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301771static int vsc85xx_config_aneg(struct phy_device *phydev)
1772{
1773 int rc;
1774
1775 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
1776 if (rc < 0)
1777 return rc;
1778
1779 return genphy_config_aneg(phydev);
1780}
1781
1782static int vsc85xx_read_status(struct phy_device *phydev)
1783{
1784 int rc;
1785
1786 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
1787 if (rc < 0)
1788 return rc;
1789
1790 return genphy_read_status(phydev);
1791}
1792
Quentin Schulz00d70d82018-10-08 12:14:43 +02001793static int vsc8574_probe(struct phy_device *phydev)
1794{
1795 struct vsc8531_private *vsc8531;
1796 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
1797 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
1798 VSC8531_DUPLEX_COLLISION};
1799
1800 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
1801 if (!vsc8531)
1802 return -ENOMEM;
1803
1804 phydev->priv = vsc8531;
1805
1806 vsc8531->nleds = 4;
1807 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
1808 vsc8531->hw_stats = vsc8584_hw_stats;
1809 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
1810 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
1811 sizeof(u64), GFP_KERNEL);
1812 if (!vsc8531->stats)
1813 return -ENOMEM;
1814
1815 return vsc85xx_dt_led_modes_get(phydev, default_mode);
1816}
1817
Quentin Schulza5afc162018-10-08 12:14:42 +02001818static int vsc8584_probe(struct phy_device *phydev)
1819{
1820 struct vsc8531_private *vsc8531;
1821 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
1822 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
1823 VSC8531_DUPLEX_COLLISION};
1824
1825 if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
1826 dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n");
1827 return -ENOTSUPP;
1828 }
1829
1830 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
1831 if (!vsc8531)
1832 return -ENOMEM;
1833
1834 phydev->priv = vsc8531;
1835
1836 vsc8531->nleds = 4;
1837 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
1838 vsc8531->hw_stats = vsc8584_hw_stats;
1839 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
1840 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
1841 sizeof(u64), GFP_KERNEL);
1842 if (!vsc8531->stats)
1843 return -ENOMEM;
1844
1845 return vsc85xx_dt_led_modes_get(phydev, default_mode);
1846}
1847
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301848static int vsc85xx_probe(struct phy_device *phydev)
1849{
1850 struct vsc8531_private *vsc8531;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +05301851 int rate_magic;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +02001852 u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001853 VSC8531_LINK_100_ACTIVITY};
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301854
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001855 rate_magic = vsc85xx_edge_rate_magic_get(phydev);
1856 if (rate_magic < 0)
1857 return rate_magic;
1858
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301859 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
1860 if (!vsc8531)
1861 return -ENOMEM;
1862
1863 phydev->priv = vsc8531;
1864
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001865 vsc8531->rate_magic = rate_magic;
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001866 vsc8531->nleds = 2;
Quentin Schulz0969aba2018-09-03 10:48:48 +02001867 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001868 vsc8531->hw_stats = vsc85xx_hw_stats;
1869 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
1870 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
1871 sizeof(u64), GFP_KERNEL);
1872 if (!vsc8531->stats)
1873 return -ENOMEM;
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001874
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001875 return vsc85xx_dt_led_modes_get(phydev, default_mode);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301876}
1877
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301878/* Microsemi VSC85xx PHYs */
1879static struct phy_driver vsc85xx_driver[] = {
1880{
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001881 .phy_id = PHY_ID_VSC8530,
1882 .name = "Microsemi FE VSC8530",
1883 .phy_id_mask = 0xfffffff0,
1884 .features = PHY_BASIC_FEATURES,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001885 .soft_reset = &genphy_soft_reset,
1886 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301887 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001888 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301889 .read_status = &vsc85xx_read_status,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001890 .ack_interrupt = &vsc85xx_ack_interrupt,
1891 .config_intr = &vsc85xx_config_intr,
1892 .suspend = &genphy_suspend,
1893 .resume = &genphy_resume,
1894 .probe = &vsc85xx_probe,
1895 .set_wol = &vsc85xx_wol_set,
1896 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001897 .get_tunable = &vsc85xx_get_tunable,
1898 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001899 .read_page = &vsc85xx_phy_read_page,
1900 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001901 .get_sset_count = &vsc85xx_get_sset_count,
1902 .get_strings = &vsc85xx_get_strings,
1903 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001904},
1905{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301906 .phy_id = PHY_ID_VSC8531,
1907 .name = "Microsemi VSC8531",
1908 .phy_id_mask = 0xfffffff0,
1909 .features = PHY_GBIT_FEATURES,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301910 .soft_reset = &genphy_soft_reset,
1911 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301912 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301913 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301914 .read_status = &vsc85xx_read_status,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301915 .ack_interrupt = &vsc85xx_ack_interrupt,
1916 .config_intr = &vsc85xx_config_intr,
1917 .suspend = &genphy_suspend,
1918 .resume = &genphy_resume,
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001919 .probe = &vsc85xx_probe,
1920 .set_wol = &vsc85xx_wol_set,
1921 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001922 .get_tunable = &vsc85xx_get_tunable,
1923 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001924 .read_page = &vsc85xx_phy_read_page,
1925 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001926 .get_sset_count = &vsc85xx_get_sset_count,
1927 .get_strings = &vsc85xx_get_strings,
1928 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301929},
1930{
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001931 .phy_id = PHY_ID_VSC8540,
1932 .name = "Microsemi FE VSC8540 SyncE",
1933 .phy_id_mask = 0xfffffff0,
1934 .features = PHY_BASIC_FEATURES,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001935 .soft_reset = &genphy_soft_reset,
1936 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301937 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001938 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301939 .read_status = &vsc85xx_read_status,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001940 .ack_interrupt = &vsc85xx_ack_interrupt,
1941 .config_intr = &vsc85xx_config_intr,
1942 .suspend = &genphy_suspend,
1943 .resume = &genphy_resume,
1944 .probe = &vsc85xx_probe,
1945 .set_wol = &vsc85xx_wol_set,
1946 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001947 .get_tunable = &vsc85xx_get_tunable,
1948 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001949 .read_page = &vsc85xx_phy_read_page,
1950 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001951 .get_sset_count = &vsc85xx_get_sset_count,
1952 .get_strings = &vsc85xx_get_strings,
1953 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001954},
1955{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301956 .phy_id = PHY_ID_VSC8541,
1957 .name = "Microsemi VSC8541 SyncE",
1958 .phy_id_mask = 0xfffffff0,
1959 .features = PHY_GBIT_FEATURES,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301960 .soft_reset = &genphy_soft_reset,
1961 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301962 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301963 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301964 .read_status = &vsc85xx_read_status,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301965 .ack_interrupt = &vsc85xx_ack_interrupt,
1966 .config_intr = &vsc85xx_config_intr,
1967 .suspend = &genphy_suspend,
1968 .resume = &genphy_resume,
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001969 .probe = &vsc85xx_probe,
1970 .set_wol = &vsc85xx_wol_set,
1971 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001972 .get_tunable = &vsc85xx_get_tunable,
1973 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001974 .read_page = &vsc85xx_phy_read_page,
1975 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001976 .get_sset_count = &vsc85xx_get_sset_count,
1977 .get_strings = &vsc85xx_get_strings,
1978 .get_stats = &vsc85xx_get_stats,
Quentin Schulza5afc162018-10-08 12:14:42 +02001979},
1980{
Quentin Schulz00d70d82018-10-08 12:14:43 +02001981 .phy_id = PHY_ID_VSC8574,
1982 .name = "Microsemi GE VSC8574 SyncE",
1983 .phy_id_mask = 0xfffffff0,
1984 .features = PHY_GBIT_FEATURES,
Quentin Schulz00d70d82018-10-08 12:14:43 +02001985 .soft_reset = &genphy_soft_reset,
1986 .config_init = &vsc8584_config_init,
1987 .config_aneg = &vsc85xx_config_aneg,
1988 .aneg_done = &genphy_aneg_done,
1989 .read_status = &vsc85xx_read_status,
1990 .ack_interrupt = &vsc85xx_ack_interrupt,
1991 .config_intr = &vsc85xx_config_intr,
1992 .did_interrupt = &vsc8584_did_interrupt,
1993 .suspend = &genphy_suspend,
1994 .resume = &genphy_resume,
1995 .probe = &vsc8574_probe,
1996 .set_wol = &vsc85xx_wol_set,
1997 .get_wol = &vsc85xx_wol_get,
1998 .get_tunable = &vsc85xx_get_tunable,
1999 .set_tunable = &vsc85xx_set_tunable,
2000 .read_page = &vsc85xx_phy_read_page,
2001 .write_page = &vsc85xx_phy_write_page,
2002 .get_sset_count = &vsc85xx_get_sset_count,
2003 .get_strings = &vsc85xx_get_strings,
2004 .get_stats = &vsc85xx_get_stats,
2005},
2006{
Quentin Schulza5afc162018-10-08 12:14:42 +02002007 .phy_id = PHY_ID_VSC8584,
2008 .name = "Microsemi GE VSC8584 SyncE",
2009 .phy_id_mask = 0xfffffff0,
2010 .features = PHY_GBIT_FEATURES,
Quentin Schulza5afc162018-10-08 12:14:42 +02002011 .soft_reset = &genphy_soft_reset,
2012 .config_init = &vsc8584_config_init,
2013 .config_aneg = &vsc85xx_config_aneg,
2014 .aneg_done = &genphy_aneg_done,
2015 .read_status = &vsc85xx_read_status,
2016 .ack_interrupt = &vsc85xx_ack_interrupt,
2017 .config_intr = &vsc85xx_config_intr,
2018 .did_interrupt = &vsc8584_did_interrupt,
2019 .suspend = &genphy_suspend,
2020 .resume = &genphy_resume,
2021 .probe = &vsc8584_probe,
2022 .get_tunable = &vsc85xx_get_tunable,
2023 .set_tunable = &vsc85xx_set_tunable,
2024 .read_page = &vsc85xx_phy_read_page,
2025 .write_page = &vsc85xx_phy_write_page,
2026 .get_sset_count = &vsc85xx_get_sset_count,
2027 .get_strings = &vsc85xx_get_strings,
2028 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302029}
2030
2031};
2032
2033module_phy_driver(vsc85xx_driver);
2034
2035static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002036 { PHY_ID_VSC8530, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302037 { PHY_ID_VSC8531, 0xfffffff0, },
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002038 { PHY_ID_VSC8540, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302039 { PHY_ID_VSC8541, 0xfffffff0, },
Quentin Schulz00d70d82018-10-08 12:14:43 +02002040 { PHY_ID_VSC8574, 0xfffffff0, },
Quentin Schulza5afc162018-10-08 12:14:42 +02002041 { PHY_ID_VSC8584, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302042 { }
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302043};
2044
2045MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
2046
2047MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
2048MODULE_AUTHOR("Nagaraju Lakkaraju");
2049MODULE_LICENSE("Dual MIT/GPL");