blob: 7cae175177449fc4eacae8a3a972bba59043ce6e [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
856static int vsc85xx_eee_init_seq_set(struct phy_device *phydev)
857{
858 const struct reg_val init_eee[] = {
859 {0x0f82, 0x0012b00a},
860 {0x1686, 0x00000004},
861 {0x168c, 0x00d2c46f},
862 {0x17a2, 0x00000620},
863 {0x16a0, 0x00eeffdd},
864 {0x16a6, 0x00071448},
865 {0x16a4, 0x0013132f},
866 {0x16a8, 0x00000000},
867 {0x0ffc, 0x00c0a028},
868 {0x0fe8, 0x0091b06c},
869 {0x0fea, 0x00041600},
870 {0x0f80, 0x00000af4},
871 {0x0fec, 0x00901809},
872 {0x0fee, 0x0000a6a1},
873 {0x0ffe, 0x00b01007},
874 {0x16b0, 0x00eeff00},
875 {0x16b2, 0x00007000},
876 {0x16b4, 0x00000814},
877 };
878 unsigned int i;
879 int oldpage;
880
881 mutex_lock(&phydev->lock);
882 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
883 if (oldpage < 0)
884 goto out_unlock;
885
886 for (i = 0; i < ARRAY_SIZE(init_eee); i++)
887 vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);
888
889out_unlock:
890 oldpage = phy_restore_page(phydev, oldpage, oldpage);
891 mutex_unlock(&phydev->lock);
892
893 return oldpage;
894}
895
Quentin Schulza5afc162018-10-08 12:14:42 +0200896/* phydev->bus->mdio_lock should be locked when using this function */
897static int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
898{
899 struct vsc8531_private *priv = phydev->priv;
900
901 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
902 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
903 dump_stack();
904 }
905
906 return __mdiobus_write(phydev->mdio.bus, priv->base_addr, regnum, val);
907}
908
909/* phydev->bus->mdio_lock should be locked when using this function */
910static int phy_base_read(struct phy_device *phydev, u32 regnum)
911{
912 struct vsc8531_private *priv = phydev->priv;
913
914 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
915 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
916 dump_stack();
917 }
918
919 return __mdiobus_read(phydev->mdio.bus, priv->base_addr, regnum);
920}
921
922/* bus->mdio_lock should be locked when using this function */
923static void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val)
924{
925 phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
926 phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
927 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
928}
929
930/* bus->mdio_lock should be locked when using this function */
931static int vsc8584_cmd(struct phy_device *phydev, u16 val)
932{
933 unsigned long deadline;
934 u16 reg_val;
935
936 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
937 MSCC_PHY_PAGE_EXTENDED_GPIO);
938
939 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val);
940
941 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
942 do {
943 reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD);
944 } while (time_before(jiffies, deadline) &&
945 (reg_val & PROC_CMD_NCOMPLETED) &&
946 !(reg_val & PROC_CMD_FAILED));
947
948 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
949
950 if (reg_val & PROC_CMD_FAILED)
951 return -EIO;
952
953 if (reg_val & PROC_CMD_NCOMPLETED)
954 return -ETIMEDOUT;
955
956 return 0;
957}
958
959/* bus->mdio_lock should be locked when using this function */
960static int vsc8584_micro_deassert_reset(struct phy_device *phydev,
961 bool patch_en)
962{
963 u32 enable, release;
964
965 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
966 MSCC_PHY_PAGE_EXTENDED_GPIO);
967
968 enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
969 release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
970 MICRO_CLK_EN;
971
972 if (patch_en) {
973 enable |= MICRO_PATCH_EN;
974 release |= MICRO_PATCH_EN;
975
976 /* Clear all patches */
977 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
978 }
979
980 /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock
981 * override and addr. auto-incr; operate at 125 MHz
982 */
983 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable);
984 /* Release 8051 Micro SW reset */
985 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release);
986
987 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
988
989 return 0;
990}
991
992/* bus->mdio_lock should be locked when using this function */
993static int vsc8584_micro_assert_reset(struct phy_device *phydev)
994{
995 int ret;
996 u16 reg;
997
998 ret = vsc8584_cmd(phydev, PROC_CMD_NOP);
999 if (ret)
1000 return ret;
1001
1002 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1003 MSCC_PHY_PAGE_EXTENDED_GPIO);
1004
1005 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1006 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
1007 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1008
1009 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b);
1010 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b);
1011
1012 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1013 reg |= EN_PATCH_RAM_TRAP_ADDR(4);
1014 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1015
1016 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
1017
1018 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
1019 reg &= ~MICRO_NSOFT_RESET;
1020 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg);
1021
1022 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF |
1023 PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF |
1024 PROC_CMD_READ);
1025
1026 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1027 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
1028 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1029
1030 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1031
1032 return 0;
1033}
1034
1035/* bus->mdio_lock should be locked when using this function */
1036static int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size,
1037 u16 *crc)
1038{
1039 int ret;
1040
1041 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1042
1043 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start);
1044 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size);
1045
1046 /* Start Micro command */
1047 ret = vsc8584_cmd(phydev, PROC_CMD_CRC16);
1048 if (ret)
1049 goto out;
1050
1051 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1052
1053 *crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
1054
1055out:
1056 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1057
1058 return ret;
1059}
1060
1061/* bus->mdio_lock should be locked when using this function */
1062static int vsc8584_patch_fw(struct phy_device *phydev,
1063 const struct firmware *fw)
1064{
1065 int i, ret;
1066
1067 ret = vsc8584_micro_assert_reset(phydev);
1068 if (ret) {
1069 dev_err(&phydev->mdio.dev,
1070 "%s: failed to assert reset of micro\n", __func__);
1071 return ret;
1072 }
1073
1074 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1075 MSCC_PHY_PAGE_EXTENDED_GPIO);
1076
1077 /* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
1078 * Disable the 8051 Micro clock
1079 */
1080 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM |
1081 AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN |
1082 MICRO_CLK_DIVIDE(2));
1083 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN |
1084 INT_MEM_DATA(2));
1085 phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000);
1086
1087 for (i = 0; i < fw->size; i++)
1088 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM |
1089 INT_MEM_WRITE_EN | fw->data[i]);
1090
1091 /* Clear internal memory access */
1092 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
1093
1094 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1095
1096 return 0;
1097}
1098
1099/* bus->mdio_lock should be locked when using this function */
Quentin Schulz00d70d82018-10-08 12:14:43 +02001100static bool vsc8574_is_serdes_init(struct phy_device *phydev)
1101{
1102 u16 reg;
1103 bool ret;
1104
1105 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1106 MSCC_PHY_PAGE_EXTENDED_GPIO);
1107
1108 reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));
1109 if (reg != 0x3eb7) {
1110 ret = false;
1111 goto out;
1112 }
1113
1114 reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));
1115 if (reg != 0x4012) {
1116 ret = false;
1117 goto out;
1118 }
1119
1120 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1121 if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
1122 ret = false;
1123 goto out;
1124 }
1125
1126 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
1127 if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
1128 MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
1129 ret = false;
1130 goto out;
1131 }
1132
1133 ret = true;
1134out:
1135 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1136
1137 return ret;
1138}
1139
1140/* bus->mdio_lock should be locked when using this function */
1141static int vsc8574_config_pre_init(struct phy_device *phydev)
1142{
1143 const struct reg_val pre_init1[] = {
1144 {0x0fae, 0x000401bd},
1145 {0x0fac, 0x000f000f},
1146 {0x17a0, 0x00a0f147},
1147 {0x0fe4, 0x00052f54},
1148 {0x1792, 0x0027303d},
1149 {0x07fe, 0x00000704},
1150 {0x0fe0, 0x00060150},
1151 {0x0f82, 0x0012b00a},
1152 {0x0f80, 0x00000d74},
1153 {0x02e0, 0x00000012},
1154 {0x03a2, 0x00050208},
1155 {0x03b2, 0x00009186},
1156 {0x0fb0, 0x000e3700},
1157 {0x1688, 0x00049f81},
1158 {0x0fd2, 0x0000ffff},
1159 {0x168a, 0x00039fa2},
1160 {0x1690, 0x0020640b},
1161 {0x0258, 0x00002220},
1162 {0x025a, 0x00002a20},
1163 {0x025c, 0x00003060},
1164 {0x025e, 0x00003fa0},
1165 {0x03a6, 0x0000e0f0},
1166 {0x0f92, 0x00001489},
1167 {0x16a2, 0x00007000},
1168 {0x16a6, 0x00071448},
1169 {0x16a0, 0x00eeffdd},
1170 {0x0fe8, 0x0091b06c},
1171 {0x0fea, 0x00041600},
1172 {0x16b0, 0x00eeff00},
1173 {0x16b2, 0x00007000},
1174 {0x16b4, 0x00000814},
1175 {0x0f90, 0x00688980},
1176 {0x03a4, 0x0000d8f0},
1177 {0x0fc0, 0x00000400},
1178 {0x07fa, 0x0050100f},
1179 {0x0796, 0x00000003},
1180 {0x07f8, 0x00c3ff98},
1181 {0x0fa4, 0x0018292a},
1182 {0x168c, 0x00d2c46f},
1183 {0x17a2, 0x00000620},
1184 {0x16a4, 0x0013132f},
1185 {0x16a8, 0x00000000},
1186 {0x0ffc, 0x00c0a028},
1187 {0x0fec, 0x00901c09},
1188 {0x0fee, 0x0004a6a1},
1189 {0x0ffe, 0x00b01807},
1190 };
1191 const struct reg_val pre_init2[] = {
1192 {0x0486, 0x0008a518},
1193 {0x0488, 0x006dc696},
1194 {0x048a, 0x00000912},
1195 {0x048e, 0x00000db6},
1196 {0x049c, 0x00596596},
1197 {0x049e, 0x00000514},
1198 {0x04a2, 0x00410280},
1199 {0x04a4, 0x00000000},
1200 {0x04a6, 0x00000000},
1201 {0x04a8, 0x00000000},
1202 {0x04aa, 0x00000000},
1203 {0x04ae, 0x007df7dd},
1204 {0x04b0, 0x006d95d4},
1205 {0x04b2, 0x00492410},
1206 };
1207 struct device *dev = &phydev->mdio.dev;
1208 const struct firmware *fw;
1209 unsigned int i;
1210 u16 crc, reg;
1211 bool serdes_init;
1212 int ret;
1213
1214 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1215
1216 /* all writes below are broadcasted to all PHYs in the same package */
1217 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1218 reg |= SMI_BROADCAST_WR_EN;
1219 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1220
1221 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
1222
1223 /* The below register writes are tweaking analog and electrical
1224 * configuration that were determined through characterization by PHY
1225 * engineers. These don't mean anything more than "these are the best
1226 * values".
1227 */
1228 phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
1229
1230 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1231
1232 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);
1233 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);
1234 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);
1235 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);
1236
1237 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1238 reg |= 0x8000;
1239 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1240
1241 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1242
1243 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1244 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1245
1246 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1247
1248 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
1249
1250 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1251
1252 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
1253 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
1254
1255 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1256
1257 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1258 reg &= ~0x8000;
1259 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1260
1261 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1262
1263 /* end of write broadcasting */
1264 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1265 reg &= ~SMI_BROADCAST_WR_EN;
1266 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1267
1268 ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);
1269 if (ret) {
1270 dev_err(dev, "failed to load firmware %s, ret: %d\n",
1271 MSCC_VSC8574_REVB_INT8051_FW, ret);
1272 return ret;
1273 }
1274
1275 /* Add one byte to size for the one added by the patch_fw function */
1276 ret = vsc8584_get_fw_crc(phydev,
1277 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
1278 fw->size + 1, &crc);
1279 if (ret)
1280 goto out;
1281
1282 if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
1283 serdes_init = vsc8574_is_serdes_init(phydev);
1284
1285 if (!serdes_init) {
1286 ret = vsc8584_micro_assert_reset(phydev);
1287 if (ret) {
1288 dev_err(dev,
1289 "%s: failed to assert reset of micro\n",
1290 __func__);
Gustavo A. R. Silva47d20212018-10-16 19:37:35 +02001291 goto out;
Quentin Schulz00d70d82018-10-08 12:14:43 +02001292 }
1293 }
1294 } else {
1295 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
1296
1297 serdes_init = false;
1298
1299 if (vsc8584_patch_fw(phydev, fw))
1300 dev_warn(dev,
1301 "failed to patch FW, expect non-optimal device\n");
1302 }
1303
1304 if (!serdes_init) {
1305 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1306 MSCC_PHY_PAGE_EXTENDED_GPIO);
1307
1308 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);
1309 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);
1310 phy_base_write(phydev, MSCC_INT_MEM_CNTL,
1311 EN_PATCH_RAM_TRAP_ADDR(1));
1312
1313 vsc8584_micro_deassert_reset(phydev, false);
1314
1315 /* Add one byte to size for the one added by the patch_fw
1316 * function
1317 */
1318 ret = vsc8584_get_fw_crc(phydev,
1319 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
1320 fw->size + 1, &crc);
1321 if (ret)
1322 goto out;
1323
1324 if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
1325 dev_warn(dev,
1326 "FW CRC after patching is not the expected one, expect non-optimal device\n");
1327 }
1328
1329 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1330 MSCC_PHY_PAGE_EXTENDED_GPIO);
1331
1332 ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |
1333 PROC_CMD_PHY_INIT);
1334
1335out:
1336 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1337
1338 release_firmware(fw);
1339
1340 return ret;
1341}
1342
1343/* bus->mdio_lock should be locked when using this function */
Quentin Schulza5afc162018-10-08 12:14:42 +02001344static int vsc8584_config_pre_init(struct phy_device *phydev)
1345{
1346 const struct reg_val pre_init1[] = {
1347 {0x07fa, 0x0050100f},
1348 {0x1688, 0x00049f81},
1349 {0x0f90, 0x00688980},
1350 {0x03a4, 0x0000d8f0},
1351 {0x0fc0, 0x00000400},
1352 {0x0f82, 0x0012b002},
1353 {0x1686, 0x00000004},
1354 {0x168c, 0x00d2c46f},
1355 {0x17a2, 0x00000620},
1356 {0x16a0, 0x00eeffdd},
1357 {0x16a6, 0x00071448},
1358 {0x16a4, 0x0013132f},
1359 {0x16a8, 0x00000000},
1360 {0x0ffc, 0x00c0a028},
1361 {0x0fe8, 0x0091b06c},
1362 {0x0fea, 0x00041600},
1363 {0x0f80, 0x00fffaff},
1364 {0x0fec, 0x00901809},
1365 {0x0ffe, 0x00b01007},
1366 {0x16b0, 0x00eeff00},
1367 {0x16b2, 0x00007000},
1368 {0x16b4, 0x00000814},
1369 };
1370 const struct reg_val pre_init2[] = {
1371 {0x0486, 0x0008a518},
1372 {0x0488, 0x006dc696},
1373 {0x048a, 0x00000912},
1374 };
1375 const struct firmware *fw;
1376 struct device *dev = &phydev->mdio.dev;
1377 unsigned int i;
1378 u16 crc, reg;
1379 int ret;
1380
1381 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1382
1383 /* all writes below are broadcasted to all PHYs in the same package */
1384 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1385 reg |= SMI_BROADCAST_WR_EN;
1386 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1387
1388 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
1389
1390 reg = phy_base_read(phydev, MSCC_PHY_BYPASS_CONTROL);
1391 reg |= PARALLEL_DET_IGNORE_ADVERTISED;
1392 phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg);
1393
1394 /* The below register writes are tweaking analog and electrical
1395 * configuration that were determined through characterization by PHY
1396 * engineers. These don't mean anything more than "these are the best
1397 * values".
1398 */
1399 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
1400
1401 phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000);
1402
1403 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1404
1405 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20);
1406
1407 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1408 reg |= 0x8000;
1409 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1410
1411 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1412
1413 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4));
1414
1415 reg = phy_base_read(phydev, MSCC_PHY_TR_MSB);
1416 reg &= ~0x007f;
1417 reg |= 0x0019;
1418 phy_base_write(phydev, MSCC_PHY_TR_MSB, reg);
1419
1420 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4));
1421
1422 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1423 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1424
1425 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1426
1427 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
1428
1429 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1430
1431 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
1432 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
1433
1434 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1435
1436 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1437 reg &= ~0x8000;
1438 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1439
1440 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1441
1442 /* end of write broadcasting */
1443 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1444 reg &= ~SMI_BROADCAST_WR_EN;
1445 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1446
1447 ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev);
1448 if (ret) {
1449 dev_err(dev, "failed to load firmware %s, ret: %d\n",
1450 MSCC_VSC8584_REVB_INT8051_FW, ret);
1451 return ret;
1452 }
1453
1454 /* Add one byte to size for the one added by the patch_fw function */
1455 ret = vsc8584_get_fw_crc(phydev,
1456 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
1457 fw->size + 1, &crc);
1458 if (ret)
1459 goto out;
1460
1461 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
1462 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
1463 if (vsc8584_patch_fw(phydev, fw))
1464 dev_warn(dev,
1465 "failed to patch FW, expect non-optimal device\n");
1466 }
1467
1468 vsc8584_micro_deassert_reset(phydev, false);
1469
1470 /* Add one byte to size for the one added by the patch_fw function */
1471 ret = vsc8584_get_fw_crc(phydev,
1472 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
1473 fw->size + 1, &crc);
1474 if (ret)
1475 goto out;
1476
1477 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
1478 dev_warn(dev,
1479 "FW CRC after patching is not the expected one, expect non-optimal device\n");
1480
1481 ret = vsc8584_micro_assert_reset(phydev);
1482 if (ret)
1483 goto out;
1484
1485 vsc8584_micro_deassert_reset(phydev, true);
1486
1487out:
1488 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1489
1490 release_firmware(fw);
1491
1492 return ret;
1493}
1494
1495/* Check if one PHY has already done the init of the parts common to all PHYs
1496 * in the Quad PHY package.
1497 */
1498static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed)
1499{
1500 struct mdio_device **map = phydev->mdio.bus->mdio_map;
1501 struct vsc8531_private *vsc8531;
1502 struct phy_device *phy;
1503 int i, addr;
1504
1505 /* VSC8584 is a Quad PHY */
1506 for (i = 0; i < 4; i++) {
1507 vsc8531 = phydev->priv;
1508
1509 if (reversed)
1510 addr = vsc8531->base_addr - i;
1511 else
1512 addr = vsc8531->base_addr + i;
1513
1514 phy = container_of(map[addr], struct phy_device, mdio);
1515
1516 if ((phy->phy_id & phydev->drv->phy_id_mask) !=
1517 (phydev->drv->phy_id & phydev->drv->phy_id_mask))
1518 continue;
1519
1520 vsc8531 = phy->priv;
1521
1522 if (vsc8531 && vsc8531->pkg_init)
1523 return true;
1524 }
1525
1526 return false;
1527}
1528
1529static int vsc8584_config_init(struct phy_device *phydev)
1530{
1531 struct vsc8531_private *vsc8531 = phydev->priv;
1532 u16 addr, val;
1533 int ret, i;
1534
1535 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1536
1537 mutex_lock(&phydev->mdio.bus->mdio_lock);
1538
1539 __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
1540 MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1541 addr = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
1542 MSCC_PHY_EXT_PHY_CNTL_4);
1543 addr >>= PHY_CNTL_4_ADDR_POS;
1544
1545 val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
1546 MSCC_PHY_ACTIPHY_CNTL);
1547 if (val & PHY_ADDR_REVERSED)
1548 vsc8531->base_addr = phydev->mdio.addr + addr;
1549 else
1550 vsc8531->base_addr = phydev->mdio.addr - addr;
1551
1552 /* Some parts of the init sequence are identical for every PHY in the
1553 * package. Some parts are modifying the GPIO register bank which is a
1554 * set of registers that are affecting all PHYs, a few resetting the
1555 * microprocessor common to all PHYs. The CRC check responsible of the
1556 * checking the firmware within the 8051 microprocessor can only be
1557 * accessed via the PHY whose internal address in the package is 0.
1558 * All PHYs' interrupts mask register has to be zeroed before enabling
1559 * any PHY's interrupt in this register.
1560 * For all these reasons, we need to do the init sequence once and only
1561 * once whatever is the first PHY in the package that is initialized and
1562 * do the correct init sequence for all PHYs that are package-critical
1563 * in this pre-init function.
1564 */
1565 if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
Quentin Schulz00d70d82018-10-08 12:14:43 +02001566 if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
1567 (PHY_ID_VSC8574 & phydev->drv->phy_id_mask))
1568 ret = vsc8574_config_pre_init(phydev);
1569 else if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
1570 (PHY_ID_VSC8584 & phydev->drv->phy_id_mask))
1571 ret = vsc8584_config_pre_init(phydev);
1572 else
1573 ret = -EINVAL;
1574
Quentin Schulza5afc162018-10-08 12:14:42 +02001575 if (ret)
1576 goto err;
1577 }
1578
1579 vsc8531->pkg_init = true;
1580
1581 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1582 MSCC_PHY_PAGE_EXTENDED_GPIO);
1583
1584 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
1585 val &= ~MAC_CFG_MASK;
1586 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1587 val |= MAC_CFG_QSGMII;
1588 else
1589 val |= MAC_CFG_SGMII;
1590
1591 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
1592 if (ret)
1593 goto err;
1594
1595 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
1596 PROC_CMD_READ_MOD_WRITE_PORT;
1597 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1598 val |= PROC_CMD_QSGMII_MAC;
1599 else
1600 val |= PROC_CMD_SGMII_MAC;
1601
1602 ret = vsc8584_cmd(phydev, val);
1603 if (ret)
1604 goto err;
1605
1606 usleep_range(10000, 20000);
1607
1608 /* Disable SerDes for 100Base-FX */
1609 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
1610 PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1611 PROC_CMD_READ_MOD_WRITE_PORT |
1612 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
1613 if (ret)
1614 goto err;
1615
1616 /* Disable SerDes for 1000Base-X */
1617 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
1618 PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1619 PROC_CMD_READ_MOD_WRITE_PORT |
1620 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
1621 if (ret)
1622 goto err;
1623
1624 mutex_unlock(&phydev->mdio.bus->mdio_lock);
1625
1626 phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1627
1628 val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
1629 val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
1630 val |= MEDIA_OP_MODE_COPPER | (VSC8584_MAC_IF_SELECTION_SGMII <<
1631 VSC8584_MAC_IF_SELECTION_POS);
1632 ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);
1633
1634 ret = genphy_soft_reset(phydev);
1635 if (ret)
1636 return ret;
1637
1638 for (i = 0; i < vsc8531->nleds; i++) {
1639 ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
1640 if (ret)
1641 return ret;
1642 }
1643
1644 return genphy_config_init(phydev);
1645
1646err:
1647 mutex_unlock(&phydev->mdio.bus->mdio_lock);
1648 return ret;
1649}
1650
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301651static int vsc85xx_config_init(struct phy_device *phydev)
1652{
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001653 int rc, i;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301654 struct vsc8531_private *vsc8531 = phydev->priv;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301655
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301656 rc = vsc85xx_default_config(phydev);
1657 if (rc)
1658 return rc;
Raju Lakkaraju1a211012016-09-19 15:33:54 +05301659
1660 rc = vsc85xx_mac_if_set(phydev, phydev->interface);
1661 if (rc)
1662 return rc;
1663
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001664 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301665 if (rc)
1666 return rc;
1667
Raju Lakkaraju96dae012018-10-08 12:07:25 +02001668 rc = vsc85xx_eee_init_seq_set(phydev);
1669 if (rc)
1670 return rc;
1671
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001672 for (i = 0; i < vsc8531->nleds; i++) {
1673 rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
1674 if (rc)
1675 return rc;
1676 }
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +05301677
Quentin Schulz629ea0f2018-10-08 12:07:28 +02001678 return genphy_config_init(phydev);
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301679}
1680
Quentin Schulza5afc162018-10-08 12:14:42 +02001681static int vsc8584_did_interrupt(struct phy_device *phydev)
1682{
1683 int rc = 0;
1684
1685 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
1686 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
1687
1688 return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
1689}
1690
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301691static int vsc85xx_ack_interrupt(struct phy_device *phydev)
1692{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301693 int rc = 0;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301694
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301695 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
1696 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301697
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301698 return (rc < 0) ? rc : 0;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301699}
1700
1701static int vsc85xx_config_intr(struct phy_device *phydev)
1702{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301703 int rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301704
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301705 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1706 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
1707 MII_VSC85XX_INT_MASK_MASK);
1708 } else {
1709 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
1710 if (rc < 0)
1711 return rc;
1712 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
1713 }
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301714
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301715 return rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301716}
1717
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301718static int vsc85xx_config_aneg(struct phy_device *phydev)
1719{
1720 int rc;
1721
1722 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
1723 if (rc < 0)
1724 return rc;
1725
1726 return genphy_config_aneg(phydev);
1727}
1728
1729static int vsc85xx_read_status(struct phy_device *phydev)
1730{
1731 int rc;
1732
1733 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
1734 if (rc < 0)
1735 return rc;
1736
1737 return genphy_read_status(phydev);
1738}
1739
Quentin Schulz00d70d82018-10-08 12:14:43 +02001740static int vsc8574_probe(struct phy_device *phydev)
1741{
1742 struct vsc8531_private *vsc8531;
1743 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
1744 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
1745 VSC8531_DUPLEX_COLLISION};
1746
1747 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
1748 if (!vsc8531)
1749 return -ENOMEM;
1750
1751 phydev->priv = vsc8531;
1752
1753 vsc8531->nleds = 4;
1754 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
1755 vsc8531->hw_stats = vsc8584_hw_stats;
1756 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
1757 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
1758 sizeof(u64), GFP_KERNEL);
1759 if (!vsc8531->stats)
1760 return -ENOMEM;
1761
1762 return vsc85xx_dt_led_modes_get(phydev, default_mode);
1763}
1764
Quentin Schulza5afc162018-10-08 12:14:42 +02001765static int vsc8584_probe(struct phy_device *phydev)
1766{
1767 struct vsc8531_private *vsc8531;
1768 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
1769 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
1770 VSC8531_DUPLEX_COLLISION};
1771
1772 if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
1773 dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n");
1774 return -ENOTSUPP;
1775 }
1776
1777 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
1778 if (!vsc8531)
1779 return -ENOMEM;
1780
1781 phydev->priv = vsc8531;
1782
1783 vsc8531->nleds = 4;
1784 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
1785 vsc8531->hw_stats = vsc8584_hw_stats;
1786 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
1787 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
1788 sizeof(u64), GFP_KERNEL);
1789 if (!vsc8531->stats)
1790 return -ENOMEM;
1791
1792 return vsc85xx_dt_led_modes_get(phydev, default_mode);
1793}
1794
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301795static int vsc85xx_probe(struct phy_device *phydev)
1796{
1797 struct vsc8531_private *vsc8531;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +05301798 int rate_magic;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +02001799 u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001800 VSC8531_LINK_100_ACTIVITY};
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301801
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001802 rate_magic = vsc85xx_edge_rate_magic_get(phydev);
1803 if (rate_magic < 0)
1804 return rate_magic;
1805
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301806 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
1807 if (!vsc8531)
1808 return -ENOMEM;
1809
1810 phydev->priv = vsc8531;
1811
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001812 vsc8531->rate_magic = rate_magic;
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001813 vsc8531->nleds = 2;
Quentin Schulz0969aba2018-09-03 10:48:48 +02001814 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001815 vsc8531->hw_stats = vsc85xx_hw_stats;
1816 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
1817 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
1818 sizeof(u64), GFP_KERNEL);
1819 if (!vsc8531->stats)
1820 return -ENOMEM;
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001821
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001822 return vsc85xx_dt_led_modes_get(phydev, default_mode);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301823}
1824
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301825/* Microsemi VSC85xx PHYs */
1826static struct phy_driver vsc85xx_driver[] = {
1827{
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001828 .phy_id = PHY_ID_VSC8530,
1829 .name = "Microsemi FE VSC8530",
1830 .phy_id_mask = 0xfffffff0,
1831 .features = PHY_BASIC_FEATURES,
1832 .flags = PHY_HAS_INTERRUPT,
1833 .soft_reset = &genphy_soft_reset,
1834 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301835 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001836 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301837 .read_status = &vsc85xx_read_status,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001838 .ack_interrupt = &vsc85xx_ack_interrupt,
1839 .config_intr = &vsc85xx_config_intr,
1840 .suspend = &genphy_suspend,
1841 .resume = &genphy_resume,
1842 .probe = &vsc85xx_probe,
1843 .set_wol = &vsc85xx_wol_set,
1844 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001845 .get_tunable = &vsc85xx_get_tunable,
1846 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001847 .read_page = &vsc85xx_phy_read_page,
1848 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001849 .get_sset_count = &vsc85xx_get_sset_count,
1850 .get_strings = &vsc85xx_get_strings,
1851 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001852},
1853{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301854 .phy_id = PHY_ID_VSC8531,
1855 .name = "Microsemi VSC8531",
1856 .phy_id_mask = 0xfffffff0,
1857 .features = PHY_GBIT_FEATURES,
1858 .flags = PHY_HAS_INTERRUPT,
1859 .soft_reset = &genphy_soft_reset,
1860 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301861 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301862 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301863 .read_status = &vsc85xx_read_status,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301864 .ack_interrupt = &vsc85xx_ack_interrupt,
1865 .config_intr = &vsc85xx_config_intr,
1866 .suspend = &genphy_suspend,
1867 .resume = &genphy_resume,
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001868 .probe = &vsc85xx_probe,
1869 .set_wol = &vsc85xx_wol_set,
1870 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001871 .get_tunable = &vsc85xx_get_tunable,
1872 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001873 .read_page = &vsc85xx_phy_read_page,
1874 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001875 .get_sset_count = &vsc85xx_get_sset_count,
1876 .get_strings = &vsc85xx_get_strings,
1877 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301878},
1879{
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001880 .phy_id = PHY_ID_VSC8540,
1881 .name = "Microsemi FE VSC8540 SyncE",
1882 .phy_id_mask = 0xfffffff0,
1883 .features = PHY_BASIC_FEATURES,
1884 .flags = PHY_HAS_INTERRUPT,
1885 .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_VSC8541,
1907 .name = "Microsemi VSC8541 SyncE",
1908 .phy_id_mask = 0xfffffff0,
1909 .features = PHY_GBIT_FEATURES,
1910 .flags = PHY_HAS_INTERRUPT,
1911 .soft_reset = &genphy_soft_reset,
1912 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301913 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301914 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05301915 .read_status = &vsc85xx_read_status,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301916 .ack_interrupt = &vsc85xx_ack_interrupt,
1917 .config_intr = &vsc85xx_config_intr,
1918 .suspend = &genphy_suspend,
1919 .resume = &genphy_resume,
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001920 .probe = &vsc85xx_probe,
1921 .set_wol = &vsc85xx_wol_set,
1922 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01001923 .get_tunable = &vsc85xx_get_tunable,
1924 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02001925 .read_page = &vsc85xx_phy_read_page,
1926 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02001927 .get_sset_count = &vsc85xx_get_sset_count,
1928 .get_strings = &vsc85xx_get_strings,
1929 .get_stats = &vsc85xx_get_stats,
Quentin Schulza5afc162018-10-08 12:14:42 +02001930},
1931{
Quentin Schulz00d70d82018-10-08 12:14:43 +02001932 .phy_id = PHY_ID_VSC8574,
1933 .name = "Microsemi GE VSC8574 SyncE",
1934 .phy_id_mask = 0xfffffff0,
1935 .features = PHY_GBIT_FEATURES,
1936 .flags = PHY_HAS_INTERRUPT,
1937 .soft_reset = &genphy_soft_reset,
1938 .config_init = &vsc8584_config_init,
1939 .config_aneg = &vsc85xx_config_aneg,
1940 .aneg_done = &genphy_aneg_done,
1941 .read_status = &vsc85xx_read_status,
1942 .ack_interrupt = &vsc85xx_ack_interrupt,
1943 .config_intr = &vsc85xx_config_intr,
1944 .did_interrupt = &vsc8584_did_interrupt,
1945 .suspend = &genphy_suspend,
1946 .resume = &genphy_resume,
1947 .probe = &vsc8574_probe,
1948 .set_wol = &vsc85xx_wol_set,
1949 .get_wol = &vsc85xx_wol_get,
1950 .get_tunable = &vsc85xx_get_tunable,
1951 .set_tunable = &vsc85xx_set_tunable,
1952 .read_page = &vsc85xx_phy_read_page,
1953 .write_page = &vsc85xx_phy_write_page,
1954 .get_sset_count = &vsc85xx_get_sset_count,
1955 .get_strings = &vsc85xx_get_strings,
1956 .get_stats = &vsc85xx_get_stats,
1957},
1958{
Quentin Schulza5afc162018-10-08 12:14:42 +02001959 .phy_id = PHY_ID_VSC8584,
1960 .name = "Microsemi GE VSC8584 SyncE",
1961 .phy_id_mask = 0xfffffff0,
1962 .features = PHY_GBIT_FEATURES,
1963 .flags = PHY_HAS_INTERRUPT,
1964 .soft_reset = &genphy_soft_reset,
1965 .config_init = &vsc8584_config_init,
1966 .config_aneg = &vsc85xx_config_aneg,
1967 .aneg_done = &genphy_aneg_done,
1968 .read_status = &vsc85xx_read_status,
1969 .ack_interrupt = &vsc85xx_ack_interrupt,
1970 .config_intr = &vsc85xx_config_intr,
1971 .did_interrupt = &vsc8584_did_interrupt,
1972 .suspend = &genphy_suspend,
1973 .resume = &genphy_resume,
1974 .probe = &vsc8584_probe,
1975 .get_tunable = &vsc85xx_get_tunable,
1976 .set_tunable = &vsc85xx_set_tunable,
1977 .read_page = &vsc85xx_phy_read_page,
1978 .write_page = &vsc85xx_phy_write_page,
1979 .get_sset_count = &vsc85xx_get_sset_count,
1980 .get_strings = &vsc85xx_get_strings,
1981 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301982}
1983
1984};
1985
1986module_phy_driver(vsc85xx_driver);
1987
1988static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001989 { PHY_ID_VSC8530, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301990 { PHY_ID_VSC8531, 0xfffffff0, },
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02001991 { PHY_ID_VSC8540, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301992 { PHY_ID_VSC8541, 0xfffffff0, },
Quentin Schulz00d70d82018-10-08 12:14:43 +02001993 { PHY_ID_VSC8574, 0xfffffff0, },
Quentin Schulza5afc162018-10-08 12:14:42 +02001994 { PHY_ID_VSC8584, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301995 { }
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301996};
1997
1998MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
1999
2000MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
2001MODULE_AUTHOR("Nagaraju Lakkaraju");
2002MODULE_LICENSE("Dual MIT/GPL");