blob: 645d354ffb4852605f19782ff60815f517d72e40 [file] [log] [blame]
Andrew Lunna2443fd2019-01-21 19:05:50 +01001// SPDX-License-Identifier: (GPL-2.0 OR MIT)
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302/*
3 * Driver for Microsemi VSC85xx PHYs
4 *
5 * Author: Nagaraju Lakkaraju
6 * License: Dual MIT/GPL
7 * Copyright (c) 2016 Microsemi Corporation
8 */
9
Quentin Schulza5afc162018-10-08 12:14:42 +020010#include <linux/firmware.h>
11#include <linux/jiffies.h>
Raju Lakkarajud50736a2016-08-05 17:54:21 +053012#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/mdio.h>
15#include <linux/mii.h>
16#include <linux/phy.h>
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +053017#include <linux/of.h>
Raju Lakkaraju0a55c122016-10-05 14:19:27 +053018#include <linux/netdevice.h>
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +053019#include <dt-bindings/net/mscc-phy-vsc8531.h>
Raju Lakkarajud50736a2016-08-05 17:54:21 +053020
21enum rgmii_rx_clock_delay {
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053022 RGMII_RX_CLK_DELAY_0_2_NS = 0,
23 RGMII_RX_CLK_DELAY_0_8_NS = 1,
24 RGMII_RX_CLK_DELAY_1_1_NS = 2,
25 RGMII_RX_CLK_DELAY_1_7_NS = 3,
26 RGMII_RX_CLK_DELAY_2_0_NS = 4,
27 RGMII_RX_CLK_DELAY_2_3_NS = 5,
28 RGMII_RX_CLK_DELAY_2_6_NS = 6,
29 RGMII_RX_CLK_DELAY_3_4_NS = 7
Raju Lakkarajud50736a2016-08-05 17:54:21 +053030};
31
Raju Lakkaraju1a211012016-09-19 15:33:54 +053032/* Microsemi VSC85xx PHY registers */
33/* IEEE 802. Std Registers */
Raju Lakkaraju233275e2016-11-29 15:16:48 +053034#define MSCC_PHY_BYPASS_CONTROL 18
35#define DISABLE_HP_AUTO_MDIX_MASK 0x0080
36#define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
37#define DISABLE_POLARITY_CORR_MASK 0x0010
Quentin Schulza5afc162018-10-08 12:14:42 +020038#define PARALLEL_DET_IGNORE_ADVERTISED 0x0008
39
40#define MSCC_PHY_EXT_CNTL_STATUS 22
41#define SMI_BROADCAST_WR_EN 0x0001
Raju Lakkaraju233275e2016-11-29 15:16:48 +053042
Raju Lakkarajuf76178d2018-10-08 12:07:24 +020043#define MSCC_PHY_ERR_RX_CNT 19
44#define MSCC_PHY_ERR_FALSE_CARRIER_CNT 20
45#define MSCC_PHY_ERR_LINK_DISCONNECT_CNT 21
46#define ERR_CNT_MASK GENMASK(7, 0)
47
Raju Lakkaraju1a211012016-09-19 15:33:54 +053048#define MSCC_PHY_EXT_PHY_CNTL_1 23
49#define MAC_IF_SELECTION_MASK 0x1800
50#define MAC_IF_SELECTION_GMII 0
51#define MAC_IF_SELECTION_RMII 1
52#define MAC_IF_SELECTION_RGMII 2
53#define MAC_IF_SELECTION_POS 11
Quentin Schulza5afc162018-10-08 12:14:42 +020054#define VSC8584_MAC_IF_SELECTION_MASK 0x1000
55#define VSC8584_MAC_IF_SELECTION_SGMII 0
56#define VSC8584_MAC_IF_SELECTION_1000BASEX 1
57#define VSC8584_MAC_IF_SELECTION_POS 12
Raju Lakkaraju1a211012016-09-19 15:33:54 +053058#define FAR_END_LOOPBACK_MODE_MASK 0x0008
Quentin Schulza5afc162018-10-08 12:14:42 +020059#define MEDIA_OP_MODE_MASK 0x0700
60#define MEDIA_OP_MODE_COPPER 0
61#define MEDIA_OP_MODE_SERDES 1
62#define MEDIA_OP_MODE_1000BASEX 2
63#define MEDIA_OP_MODE_100BASEFX 3
64#define MEDIA_OP_MODE_AMS_COPPER_SERDES 5
65#define MEDIA_OP_MODE_AMS_COPPER_1000BASEX 6
66#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX 7
67#define MEDIA_OP_MODE_POS 8
Raju Lakkaraju1a211012016-09-19 15:33:54 +053068
Quentin Schulz00d70d82018-10-08 12:14:43 +020069#define MSCC_PHY_EXT_PHY_CNTL_2 24
70
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053071#define MII_VSC85XX_INT_MASK 25
72#define MII_VSC85XX_INT_MASK_MASK 0xa000
Raju Lakkaraju0a55c122016-10-05 14:19:27 +053073#define MII_VSC85XX_INT_MASK_WOL 0x0040
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +053074#define MII_VSC85XX_INT_STATUS 26
Raju Lakkarajud50736a2016-08-05 17:54:21 +053075
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +053076#define MSCC_PHY_WOL_MAC_CONTROL 27
77#define EDGE_RATE_CNTL_POS 5
78#define EDGE_RATE_CNTL_MASK 0x00E0
79
Raju Lakkaraju233275e2016-11-29 15:16:48 +053080#define MSCC_PHY_DEV_AUX_CNTL 28
81#define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
82
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +053083#define MSCC_PHY_LED_MODE_SEL 29
Quentin Schulz11bfdab2018-09-03 10:48:47 +020084#define LED_MODE_SEL_POS(x) ((x) * 4)
85#define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
86#define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +053087
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +000088#define MSCC_EXT_PAGE_CSR_CNTL_17 17
89#define MSCC_EXT_PAGE_CSR_CNTL_18 18
90
91#define MSCC_EXT_PAGE_CSR_CNTL_19 19
92#define MSCC_PHY_CSR_CNTL_19_REG_ADDR(x) (x)
93#define MSCC_PHY_CSR_CNTL_19_TARGET(x) ((x) << 12)
94#define MSCC_PHY_CSR_CNTL_19_READ BIT(14)
95#define MSCC_PHY_CSR_CNTL_19_CMD BIT(15)
96
97#define MSCC_EXT_PAGE_CSR_CNTL_20 20
98#define MSCC_PHY_CSR_CNTL_20_TARGET(x) (x)
99
100#define PHY_MCB_TARGET 0x07
101#define PHY_MCB_S6G_WRITE BIT(31)
102#define PHY_MCB_S6G_READ BIT(30)
103
104#define PHY_S6G_PLL5G_CFG0 0x06
105#define PHY_S6G_LCPLL_CFG 0x11
106#define PHY_S6G_PLL_CFG 0x2b
107#define PHY_S6G_COMMON_CFG 0x2c
108#define PHY_S6G_GPC_CFG 0x2e
109#define PHY_S6G_MISC_CFG 0x3b
110#define PHY_MCB_S6G_CFG 0x3f
111#define PHY_S6G_DFT_CFG2 0x3e
112#define PHY_S6G_PLL_STATUS 0x31
113#define PHY_S6G_IB_STATUS0 0x2f
114
115#define PHY_S6G_SYS_RST_POS 31
116#define PHY_S6G_ENA_LANE_POS 18
117#define PHY_S6G_ENA_LOOP_POS 8
118#define PHY_S6G_QRATE_POS 6
119#define PHY_S6G_IF_MODE_POS 4
120#define PHY_S6G_PLL_ENA_OFFS_POS 21
121#define PHY_S6G_PLL_FSM_CTRL_DATA_POS 8
122#define PHY_S6G_PLL_FSM_ENA_POS 7
123
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530124#define MSCC_EXT_PAGE_ACCESS 31
125#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100126#define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530127#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
Quentin Schulza5afc162018-10-08 12:14:42 +0200128#define MSCC_PHY_PAGE_EXTENDED_3 0x0003 /* Extended reg - page 3 */
129#define MSCC_PHY_PAGE_EXTENDED_4 0x0004 /* Extended reg - page 4 */
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +0000130#define MSCC_PHY_PAGE_CSR_CNTL MSCC_PHY_PAGE_EXTENDED_4
Quentin Schulza5afc162018-10-08 12:14:42 +0200131/* Extended reg - GPIO; this is a bank of registers that are shared for all PHYs
132 * in the same package.
133 */
134#define MSCC_PHY_PAGE_EXTENDED_GPIO 0x0010 /* Extended reg - GPIO */
135#define MSCC_PHY_PAGE_TEST 0x2a30 /* Test reg */
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200136#define MSCC_PHY_PAGE_TR 0x52b5 /* Token ring registers */
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530137
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100138/* Extended Page 1 Registers */
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200139#define MSCC_PHY_CU_MEDIA_CRC_VALID_CNT 18
140#define VALID_CRC_CNT_CRC_MASK GENMASK(13, 0)
141
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530142#define MSCC_PHY_EXT_MODE_CNTL 19
143#define FORCE_MDI_CROSSOVER_MASK 0x000C
144#define FORCE_MDI_CROSSOVER_MDIX 0x000C
145#define FORCE_MDI_CROSSOVER_MDI 0x0008
146
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100147#define MSCC_PHY_ACTIPHY_CNTL 20
Quentin Schulza5afc162018-10-08 12:14:42 +0200148#define PHY_ADDR_REVERSED 0x0200
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100149#define DOWNSHIFT_CNTL_MASK 0x001C
150#define DOWNSHIFT_EN 0x0010
151#define DOWNSHIFT_CNTL_POS 2
152
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200153#define MSCC_PHY_EXT_PHY_CNTL_4 23
Quentin Schulza5afc162018-10-08 12:14:42 +0200154#define PHY_CNTL_4_ADDR_POS 11
155
156#define MSCC_PHY_VERIPHY_CNTL_2 25
157
158#define MSCC_PHY_VERIPHY_CNTL_3 26
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200159
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530160/* Extended Page 2 Registers */
Quentin Schulza5afc162018-10-08 12:14:42 +0200161#define MSCC_PHY_CU_PMD_TX_CNTL 16
162
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530163#define MSCC_PHY_RGMII_CNTL 20
164#define RGMII_RX_CLK_DELAY_MASK 0x0070
165#define RGMII_RX_CLK_DELAY_POS 4
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530166
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530167#define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
168#define MSCC_PHY_WOL_MID_MAC_ADDR 22
169#define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
170#define MSCC_PHY_WOL_LOWER_PASSWD 24
171#define MSCC_PHY_WOL_MID_PASSWD 25
172#define MSCC_PHY_WOL_UPPER_PASSWD 26
173
174#define MSCC_PHY_WOL_MAC_CONTROL 27
175#define SECURE_ON_ENABLE 0x8000
176#define SECURE_ON_PASSWD_LEN_4 0x4000
177
Quentin Schulza5afc162018-10-08 12:14:42 +0200178/* Extended Page 3 Registers */
179#define MSCC_PHY_SERDES_TX_VALID_CNT 21
180#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22
181#define MSCC_PHY_SERDES_RX_VALID_CNT 28
182#define MSCC_PHY_SERDES_RX_CRC_ERR_CNT 29
183
184/* Extended page GPIO Registers */
185#define MSCC_DW8051_CNTL_STATUS 0
186#define MICRO_NSOFT_RESET 0x8000
187#define RUN_FROM_INT_ROM 0x4000
188#define AUTOINC_ADDR 0x2000
189#define PATCH_RAM_CLK 0x1000
190#define MICRO_PATCH_EN 0x0080
191#define DW8051_CLK_EN 0x0010
192#define MICRO_CLK_EN 0x0008
193#define MICRO_CLK_DIVIDE(x) ((x) >> 1)
Quentin Schulz00d70d82018-10-08 12:14:43 +0200194#define MSCC_DW8051_VLD_MASK 0xf1ff
Quentin Schulza5afc162018-10-08 12:14:42 +0200195
196/* x Address in range 1-4 */
197#define MSCC_TRAP_ROM_ADDR(x) ((x) * 2 + 1)
198#define MSCC_PATCH_RAM_ADDR(x) (((x) + 1) * 2)
199#define MSCC_INT_MEM_ADDR 11
200
201#define MSCC_INT_MEM_CNTL 12
202#define READ_SFR 0x6000
203#define READ_PRAM 0x4000
204#define READ_ROM 0x2000
205#define READ_RAM 0x0000
206#define INT_MEM_WRITE_EN 0x1000
207#define EN_PATCH_RAM_TRAP_ADDR(x) (0x0100 << ((x) - 1))
208#define INT_MEM_DATA_M 0x00ff
209#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
210
211#define MSCC_PHY_PROC_CMD 18
212#define PROC_CMD_NCOMPLETED 0x8000
213#define PROC_CMD_FAILED 0x4000
214#define PROC_CMD_SGMII_PORT(x) ((x) << 8)
215#define PROC_CMD_FIBER_PORT(x) (0x0100 << (x) % 4)
216#define PROC_CMD_QSGMII_PORT 0x0c00
217#define PROC_CMD_RST_CONF_PORT 0x0080
218#define PROC_CMD_RECONF_PORT 0x0000
219#define PROC_CMD_READ_MOD_WRITE_PORT 0x0040
220#define PROC_CMD_WRITE 0x0040
221#define PROC_CMD_READ 0x0000
222#define PROC_CMD_FIBER_DISABLE 0x0020
223#define PROC_CMD_FIBER_100BASE_FX 0x0010
224#define PROC_CMD_FIBER_1000BASE_X 0x0000
225#define PROC_CMD_SGMII_MAC 0x0030
226#define PROC_CMD_QSGMII_MAC 0x0020
227#define PROC_CMD_NO_MAC_CONF 0x0000
Quentin Schulz00d70d82018-10-08 12:14:43 +0200228#define PROC_CMD_1588_DEFAULT_INIT 0x0010
Quentin Schulza5afc162018-10-08 12:14:42 +0200229#define PROC_CMD_NOP 0x000f
Quentin Schulz00d70d82018-10-08 12:14:43 +0200230#define PROC_CMD_PHY_INIT 0x000a
Quentin Schulza5afc162018-10-08 12:14:42 +0200231#define PROC_CMD_CRC16 0x0008
232#define PROC_CMD_FIBER_MEDIA_CONF 0x0001
233#define PROC_CMD_MCB_ACCESS_MAC_CONF 0x0000
234#define PROC_CMD_NCOMPLETED_TIMEOUT_MS 500
235
236#define MSCC_PHY_MAC_CFG_FASTLINK 19
237#define MAC_CFG_MASK 0xc000
238#define MAC_CFG_SGMII 0x0000
239#define MAC_CFG_QSGMII 0x4000
240
241/* Test page Registers */
242#define MSCC_PHY_TEST_PAGE_5 5
243#define MSCC_PHY_TEST_PAGE_8 8
Quentin Schulz00d70d82018-10-08 12:14:43 +0200244#define MSCC_PHY_TEST_PAGE_9 9
245#define MSCC_PHY_TEST_PAGE_20 20
246#define MSCC_PHY_TEST_PAGE_24 24
Quentin Schulza5afc162018-10-08 12:14:42 +0200247
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200248/* Token ring page Registers */
249#define MSCC_PHY_TR_CNTL 16
250#define TR_WRITE 0x8000
251#define TR_ADDR(x) (0x7fff & (x))
252#define MSCC_PHY_TR_LSB 17
253#define MSCC_PHY_TR_MSB 18
254
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530255/* Microsemi PHY ID's */
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +0000256#define PHY_ID_VSC8514 0x00070670
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +0200257#define PHY_ID_VSC8530 0x00070560
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530258#define PHY_ID_VSC8531 0x00070570
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +0200259#define PHY_ID_VSC8540 0x00070760
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530260#define PHY_ID_VSC8541 0x00070770
Quentin Schulz00d70d82018-10-08 12:14:43 +0200261#define PHY_ID_VSC8574 0x000704a0
Quentin Schulza5afc162018-10-08 12:14:42 +0200262#define PHY_ID_VSC8584 0x000707c0
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530263
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200264#define MSCC_VDDMAC_1500 1500
265#define MSCC_VDDMAC_1800 1800
266#define MSCC_VDDMAC_2500 2500
267#define MSCC_VDDMAC_3300 3300
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530268
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100269#define DOWNSHIFT_COUNT_MAX 5
270
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200271#define MAX_LEDS 4
Quentin Schulza5afc162018-10-08 12:14:42 +0200272
273#define VSC8584_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
274 BIT(VSC8531_LINK_1000_ACTIVITY) | \
275 BIT(VSC8531_LINK_100_ACTIVITY) | \
276 BIT(VSC8531_LINK_10_ACTIVITY) | \
277 BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
278 BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
279 BIT(VSC8531_LINK_10_100_ACTIVITY) | \
280 BIT(VSC8584_LINK_100FX_1000X_ACTIVITY) | \
281 BIT(VSC8531_DUPLEX_COLLISION) | \
282 BIT(VSC8531_COLLISION) | \
283 BIT(VSC8531_ACTIVITY) | \
284 BIT(VSC8584_100FX_1000X_ACTIVITY) | \
285 BIT(VSC8531_AUTONEG_FAULT) | \
286 BIT(VSC8531_SERIAL_MODE) | \
287 BIT(VSC8531_FORCE_LED_OFF) | \
288 BIT(VSC8531_FORCE_LED_ON))
289
Quentin Schulz0969aba2018-09-03 10:48:48 +0200290#define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
291 BIT(VSC8531_LINK_1000_ACTIVITY) | \
292 BIT(VSC8531_LINK_100_ACTIVITY) | \
293 BIT(VSC8531_LINK_10_ACTIVITY) | \
294 BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
295 BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
296 BIT(VSC8531_LINK_10_100_ACTIVITY) | \
297 BIT(VSC8531_DUPLEX_COLLISION) | \
298 BIT(VSC8531_COLLISION) | \
299 BIT(VSC8531_ACTIVITY) | \
300 BIT(VSC8531_AUTONEG_FAULT) | \
301 BIT(VSC8531_SERIAL_MODE) | \
302 BIT(VSC8531_FORCE_LED_OFF) | \
303 BIT(VSC8531_FORCE_LED_ON))
304
Quentin Schulza5afc162018-10-08 12:14:42 +0200305#define MSCC_VSC8584_REVB_INT8051_FW "mscc_vsc8584_revb_int8051_fb48.bin"
306#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR 0xe800
307#define MSCC_VSC8584_REVB_INT8051_FW_CRC 0xfb48
308
Quentin Schulz00d70d82018-10-08 12:14:43 +0200309#define MSCC_VSC8574_REVB_INT8051_FW "mscc_vsc8574_revb_int8051_29e8.bin"
310#define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR 0x4000
311#define MSCC_VSC8574_REVB_INT8051_FW_CRC 0x29e8
312
Quentin Schulza5afc162018-10-08 12:14:42 +0200313#define VSC8584_REVB 0x0001
314#define MSCC_DEV_REV_MASK GENMASK(3, 0)
315
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200316struct reg_val {
317 u16 reg;
318 u32 val;
319};
320
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200321struct vsc85xx_hw_stat {
322 const char *string;
323 u8 reg;
324 u16 page;
325 u16 mask;
326};
327
328static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = {
329 {
330 .string = "phy_receive_errors",
331 .reg = MSCC_PHY_ERR_RX_CNT,
332 .page = MSCC_PHY_PAGE_STANDARD,
333 .mask = ERR_CNT_MASK,
334 }, {
335 .string = "phy_false_carrier",
336 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
337 .page = MSCC_PHY_PAGE_STANDARD,
338 .mask = ERR_CNT_MASK,
339 }, {
340 .string = "phy_cu_media_link_disconnect",
341 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
342 .page = MSCC_PHY_PAGE_STANDARD,
343 .mask = ERR_CNT_MASK,
344 }, {
345 .string = "phy_cu_media_crc_good_count",
346 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
347 .page = MSCC_PHY_PAGE_EXTENDED,
348 .mask = VALID_CRC_CNT_CRC_MASK,
349 }, {
350 .string = "phy_cu_media_crc_error_count",
351 .reg = MSCC_PHY_EXT_PHY_CNTL_4,
352 .page = MSCC_PHY_PAGE_EXTENDED,
353 .mask = ERR_CNT_MASK,
354 },
355};
356
Quentin Schulza5afc162018-10-08 12:14:42 +0200357static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
358 {
359 .string = "phy_receive_errors",
360 .reg = MSCC_PHY_ERR_RX_CNT,
361 .page = MSCC_PHY_PAGE_STANDARD,
362 .mask = ERR_CNT_MASK,
363 }, {
364 .string = "phy_false_carrier",
365 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
366 .page = MSCC_PHY_PAGE_STANDARD,
367 .mask = ERR_CNT_MASK,
368 }, {
369 .string = "phy_cu_media_link_disconnect",
370 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
371 .page = MSCC_PHY_PAGE_STANDARD,
372 .mask = ERR_CNT_MASK,
373 }, {
374 .string = "phy_cu_media_crc_good_count",
375 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
376 .page = MSCC_PHY_PAGE_EXTENDED,
377 .mask = VALID_CRC_CNT_CRC_MASK,
378 }, {
379 .string = "phy_cu_media_crc_error_count",
380 .reg = MSCC_PHY_EXT_PHY_CNTL_4,
381 .page = MSCC_PHY_PAGE_EXTENDED,
382 .mask = ERR_CNT_MASK,
383 }, {
384 .string = "phy_serdes_tx_good_pkt_count",
385 .reg = MSCC_PHY_SERDES_TX_VALID_CNT,
386 .page = MSCC_PHY_PAGE_EXTENDED_3,
387 .mask = VALID_CRC_CNT_CRC_MASK,
388 }, {
389 .string = "phy_serdes_tx_bad_crc_count",
390 .reg = MSCC_PHY_SERDES_TX_CRC_ERR_CNT,
391 .page = MSCC_PHY_PAGE_EXTENDED_3,
392 .mask = ERR_CNT_MASK,
393 }, {
394 .string = "phy_serdes_rx_good_pkt_count",
395 .reg = MSCC_PHY_SERDES_RX_VALID_CNT,
396 .page = MSCC_PHY_PAGE_EXTENDED_3,
397 .mask = VALID_CRC_CNT_CRC_MASK,
398 }, {
399 .string = "phy_serdes_rx_bad_crc_count",
400 .reg = MSCC_PHY_SERDES_RX_CRC_ERR_CNT,
401 .page = MSCC_PHY_PAGE_EXTENDED_3,
402 .mask = ERR_CNT_MASK,
403 },
404};
405
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530406struct vsc8531_private {
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200407 int rate_magic;
Quentin Schulz0969aba2018-09-03 10:48:48 +0200408 u16 supp_led_modes;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200409 u32 leds_mode[MAX_LEDS];
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200410 u8 nleds;
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200411 const struct vsc85xx_hw_stat *hw_stats;
412 u64 *stats;
413 int nstats;
Quentin Schulza5afc162018-10-08 12:14:42 +0200414 bool pkg_init;
415 /* For multiple port PHYs; the MDIO address of the base PHY in the
416 * package.
417 */
418 unsigned int base_addr;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530419};
420
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200421#ifdef CONFIG_OF_MDIO
422struct vsc8531_edge_rate_table {
Quentin Schulza993e0f2018-09-03 10:48:49 +0200423 u32 vddmac;
Quentin Schulz36c53cf2018-09-03 10:48:50 +0200424 u32 slowdown[8];
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200425};
426
427static const struct vsc8531_edge_rate_table edge_table[] = {
428 {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },
429 {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },
430 {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },
431 {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
432};
433#endif /* CONFIG_OF_MDIO */
434
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200435static int vsc85xx_phy_read_page(struct phy_device *phydev)
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530436{
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200437 return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);
438}
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530439
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200440static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
441{
442 return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530443}
444
Raju Lakkarajuf76178d2018-10-08 12:07:24 +0200445static int vsc85xx_get_sset_count(struct phy_device *phydev)
446{
447 struct vsc8531_private *priv = phydev->priv;
448
449 if (!priv)
450 return 0;
451
452 return priv->nstats;
453}
454
455static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)
456{
457 struct vsc8531_private *priv = phydev->priv;
458 int i;
459
460 if (!priv)
461 return;
462
463 for (i = 0; i < priv->nstats; i++)
464 strlcpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,
465 ETH_GSTRING_LEN);
466}
467
468static u64 vsc85xx_get_stat(struct phy_device *phydev, int i)
469{
470 struct vsc8531_private *priv = phydev->priv;
471 int val;
472
473 val = phy_read_paged(phydev, priv->hw_stats[i].page,
474 priv->hw_stats[i].reg);
475 if (val < 0)
476 return U64_MAX;
477
478 val = val & priv->hw_stats[i].mask;
479 priv->stats[i] += val;
480
481 return priv->stats[i];
482}
483
484static void vsc85xx_get_stats(struct phy_device *phydev,
485 struct ethtool_stats *stats, u64 *data)
486{
487 struct vsc8531_private *priv = phydev->priv;
488 int i;
489
490 if (!priv)
491 return;
492
493 for (i = 0; i < priv->nstats; i++)
494 data[i] = vsc85xx_get_stat(phydev, i);
495}
496
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530497static int vsc85xx_led_cntl_set(struct phy_device *phydev,
498 u8 led_num,
499 u8 mode)
500{
501 int rc;
502 u16 reg_val;
503
504 mutex_lock(&phydev->lock);
505 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200506 reg_val &= ~LED_MODE_SEL_MASK(led_num);
507 reg_val |= LED_MODE_SEL(led_num, (u16)mode);
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530508 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
509 mutex_unlock(&phydev->lock);
510
511 return rc;
512}
513
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530514static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
515{
516 u16 reg_val;
517
518 reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
519 if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
520 *mdix = ETH_TP_MDI_X;
521 else
522 *mdix = ETH_TP_MDI;
523
524 return 0;
525}
526
527static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
528{
529 int rc;
530 u16 reg_val;
531
532 reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
Quentin Schulzb7d373c2018-10-08 12:07:26 +0200533 if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) {
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530534 reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
535 DISABLE_POLARITY_CORR_MASK |
536 DISABLE_HP_AUTO_MDIX_MASK);
537 } else {
538 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
539 DISABLE_POLARITY_CORR_MASK |
540 DISABLE_HP_AUTO_MDIX_MASK);
541 }
542 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200543 if (rc)
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530544 return rc;
545
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200546 reg_val = 0;
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530547
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530548 if (mdix == ETH_TP_MDI)
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200549 reg_val = FORCE_MDI_CROSSOVER_MDI;
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530550 else if (mdix == ETH_TP_MDI_X)
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200551 reg_val = FORCE_MDI_CROSSOVER_MDIX;
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530552
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200553 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
554 MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,
555 reg_val);
556 if (rc < 0)
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530557 return rc;
558
559 return genphy_restart_aneg(phydev);
560}
561
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100562static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
563{
Gustavo A. R. Silvae5198692018-10-16 19:35:11 +0200564 int reg_val;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100565
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200566 reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
567 MSCC_PHY_ACTIPHY_CNTL);
568 if (reg_val < 0)
569 return reg_val;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100570
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100571 reg_val &= DOWNSHIFT_CNTL_MASK;
572 if (!(reg_val & DOWNSHIFT_EN))
573 *count = DOWNSHIFT_DEV_DISABLE;
574 else
575 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100576
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200577 return 0;
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100578}
579
580static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
581{
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100582 if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
583 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
584 count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
585 } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
586 phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
587 return -ERANGE;
588 } else if (count) {
589 /* Downshift count is either 2,3,4 or 5 */
590 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
591 }
592
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200593 return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
594 MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,
595 count);
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100596}
597
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530598static int vsc85xx_wol_set(struct phy_device *phydev,
599 struct ethtool_wolinfo *wol)
600{
601 int rc;
602 u16 reg_val;
603 u8 i;
604 u16 pwd[3] = {0, 0, 0};
605 struct ethtool_wolinfo *wol_conf = wol;
606 u8 *mac_addr = phydev->attached_dev->dev_addr;
607
608 mutex_lock(&phydev->lock);
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200609 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
610 if (rc < 0) {
611 rc = phy_restore_page(phydev, rc, rc);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530612 goto out_unlock;
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200613 }
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530614
615 if (wol->wolopts & WAKE_MAGIC) {
616 /* Store the device address for the magic packet */
617 for (i = 0; i < ARRAY_SIZE(pwd); i++)
618 pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
619 mac_addr[5 - i * 2];
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200620 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
621 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
622 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530623 } else {
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200624 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
625 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
626 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530627 }
628
629 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
630 for (i = 0; i < ARRAY_SIZE(pwd); i++)
631 pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
632 wol_conf->sopass[5 - i * 2];
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200633 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
634 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
635 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530636 } else {
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200637 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
638 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
639 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530640 }
641
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200642 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530643 if (wol_conf->wolopts & WAKE_MAGICSECURE)
644 reg_val |= SECURE_ON_ENABLE;
645 else
646 reg_val &= ~SECURE_ON_ENABLE;
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200647 __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530648
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200649 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
650 if (rc < 0)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530651 goto out_unlock;
652
653 if (wol->wolopts & WAKE_MAGIC) {
654 /* Enable the WOL interrupt */
655 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
656 reg_val |= MII_VSC85XX_INT_MASK_WOL;
657 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200658 if (rc)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530659 goto out_unlock;
660 } else {
661 /* Disable the WOL interrupt */
662 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
663 reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
664 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200665 if (rc)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530666 goto out_unlock;
667 }
668 /* Clear WOL iterrupt status */
669 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
670
671out_unlock:
672 mutex_unlock(&phydev->lock);
673
674 return rc;
675}
676
677static void vsc85xx_wol_get(struct phy_device *phydev,
678 struct ethtool_wolinfo *wol)
679{
680 int rc;
681 u16 reg_val;
682 u8 i;
683 u16 pwd[3] = {0, 0, 0};
684 struct ethtool_wolinfo *wol_conf = wol;
685
686 mutex_lock(&phydev->lock);
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200687 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
688 if (rc < 0)
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530689 goto out_unlock;
690
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200691 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530692 if (reg_val & SECURE_ON_ENABLE)
693 wol_conf->wolopts |= WAKE_MAGICSECURE;
694 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200695 pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
696 pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
697 pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530698 for (i = 0; i < ARRAY_SIZE(pwd); i++) {
699 wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
700 wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
701 >> 8;
702 }
703 }
704
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530705out_unlock:
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200706 phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
Raju Lakkaraju0a55c122016-10-05 14:19:27 +0530707 mutex_unlock(&phydev->lock);
708}
709
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200710#ifdef CONFIG_OF_MDIO
711static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530712{
Quentin Schulz36c53cf2018-09-03 10:48:50 +0200713 u32 vdd, sd;
Quentin Schulz629ea0f2018-10-08 12:07:28 +0200714 int i, j;
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200715 struct device *dev = &phydev->mdio.dev;
716 struct device_node *of_node = dev->of_node;
717 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530718
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200719 if (!of_node)
720 return -ENODEV;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530721
Quentin Schulz629ea0f2018-10-08 12:07:28 +0200722 if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd))
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200723 vdd = MSCC_VDDMAC_3300;
724
Quentin Schulz629ea0f2018-10-08 12:07:28 +0200725 if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd))
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200726 sd = 0;
727
728 for (i = 0; i < ARRAY_SIZE(edge_table); i++)
729 if (edge_table[i].vddmac == vdd)
730 for (j = 0; j < sd_array_size; j++)
731 if (edge_table[i].slowdown[j] == sd)
732 return (sd_array_size - j - 1);
733
734 return -EINVAL;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530735}
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530736
737static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
738 char *led,
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200739 u32 default_mode)
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530740{
Quentin Schulz0969aba2018-09-03 10:48:48 +0200741 struct vsc8531_private *priv = phydev->priv;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530742 struct device *dev = &phydev->mdio.dev;
743 struct device_node *of_node = dev->of_node;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200744 u32 led_mode;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530745 int err;
746
747 if (!of_node)
748 return -ENODEV;
749
750 led_mode = default_mode;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200751 err = of_property_read_u32(of_node, led, &led_mode);
Quentin Schulz0969aba2018-09-03 10:48:48 +0200752 if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530753 phydev_err(phydev, "DT %s invalid\n", led);
754 return -EINVAL;
755 }
756
757 return led_mode;
758}
759
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200760#else
761static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
762{
763 return 0;
764}
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +0530765
766static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
767 char *led,
768 u8 default_mode)
769{
770 return default_mode;
771}
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200772#endif /* CONFIG_OF_MDIO */
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530773
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +0200774static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
775 u32 *default_mode)
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200776{
777 struct vsc8531_private *priv = phydev->priv;
Arnd Bergmann31bae7d2018-09-26 15:20:11 +0200778 char led_dt_prop[28];
Quentin Schulz11bfdab2018-09-03 10:48:47 +0200779 int i, ret;
780
781 for (i = 0; i < priv->nleds; i++) {
782 ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
783 if (ret < 0)
784 return ret;
785
786 ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,
787 default_mode[i]);
788 if (ret < 0)
789 return ret;
790 priv->leds_mode[i] = ret;
791 }
792
793 return 0;
794}
795
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +0200796static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530797{
798 int rc;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530799
800 mutex_lock(&phydev->lock);
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +0200801 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
802 MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,
803 edge_rate << EDGE_RATE_CNTL_POS);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +0530804 mutex_unlock(&phydev->lock);
805
806 return rc;
807}
808
Raju Lakkaraju1a211012016-09-19 15:33:54 +0530809static int vsc85xx_mac_if_set(struct phy_device *phydev,
810 phy_interface_t interface)
811{
812 int rc;
813 u16 reg_val;
814
815 mutex_lock(&phydev->lock);
816 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
817 reg_val &= ~(MAC_IF_SELECTION_MASK);
818 switch (interface) {
819 case PHY_INTERFACE_MODE_RGMII:
820 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
821 break;
822 case PHY_INTERFACE_MODE_RMII:
823 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
824 break;
825 case PHY_INTERFACE_MODE_MII:
826 case PHY_INTERFACE_MODE_GMII:
827 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
828 break;
829 default:
830 rc = -EINVAL;
831 goto out_unlock;
832 }
833 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
Quentin Schulz6f0430c2018-10-08 12:07:27 +0200834 if (rc)
Raju Lakkaraju1a211012016-09-19 15:33:54 +0530835 goto out_unlock;
836
837 rc = genphy_soft_reset(phydev);
838
839out_unlock:
840 mutex_unlock(&phydev->lock);
841
842 return rc;
843}
844
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530845static int vsc85xx_default_config(struct phy_device *phydev)
846{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530847 int rc;
848 u16 reg_val;
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530849
Raju Lakkaraju233275e2016-11-29 15:16:48 +0530850 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530851 mutex_lock(&phydev->lock);
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530852
Quentin Schulz3fa528b2018-11-23 19:01:51 +0100853 reg_val = RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS;
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530854
Quentin Schulz3fa528b2018-11-23 19:01:51 +0100855 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
856 MSCC_PHY_RGMII_CNTL, RGMII_RX_CLK_DELAY_MASK,
857 reg_val);
858
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530859 mutex_unlock(&phydev->lock);
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530860
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +0530861 return rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +0530862}
863
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +0100864static int vsc85xx_get_tunable(struct phy_device *phydev,
865 struct ethtool_tunable *tuna, void *data)
866{
867 switch (tuna->id) {
868 case ETHTOOL_PHY_DOWNSHIFT:
869 return vsc85xx_downshift_get(phydev, (u8 *)data);
870 default:
871 return -EINVAL;
872 }
873}
874
875static int vsc85xx_set_tunable(struct phy_device *phydev,
876 struct ethtool_tunable *tuna,
877 const void *data)
878{
879 switch (tuna->id) {
880 case ETHTOOL_PHY_DOWNSHIFT:
881 return vsc85xx_downshift_set(phydev, *(u8 *)data);
882 default:
883 return -EINVAL;
884 }
885}
886
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200887/* mdiobus lock should be locked when using this function */
888static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val)
889{
890 __phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
891 __phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
892 __phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
893}
894
Raju Lakkaraju7b98f632018-12-18 14:57:56 +0530895static int vsc8531_pre_init_seq_set(struct phy_device *phydev)
896{
897 int rc;
898 const struct reg_val init_seq[] = {
899 {0x0f90, 0x00688980},
900 {0x0696, 0x00000003},
901 {0x07fa, 0x0050100f},
902 {0x1686, 0x00000004},
903 };
904 unsigned int i;
905 int oldpage;
906
907 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_STANDARD,
908 MSCC_PHY_EXT_CNTL_STATUS, SMI_BROADCAST_WR_EN,
909 SMI_BROADCAST_WR_EN);
910 if (rc < 0)
911 return rc;
912 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
913 MSCC_PHY_TEST_PAGE_24, 0, 0x0400);
914 if (rc < 0)
915 return rc;
916 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
917 MSCC_PHY_TEST_PAGE_5, 0x0a00, 0x0e00);
918 if (rc < 0)
919 return rc;
920 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
921 MSCC_PHY_TEST_PAGE_8, 0x8000, 0x8000);
922 if (rc < 0)
923 return rc;
924
925 mutex_lock(&phydev->lock);
926 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
927 if (oldpage < 0)
928 goto out_unlock;
929
930 for (i = 0; i < ARRAY_SIZE(init_seq); i++)
931 vsc85xx_tr_write(phydev, init_seq[i].reg, init_seq[i].val);
932
933out_unlock:
934 oldpage = phy_restore_page(phydev, oldpage, oldpage);
935 mutex_unlock(&phydev->lock);
936
937 return oldpage;
938}
939
Raju Lakkaraju96dae012018-10-08 12:07:25 +0200940static int vsc85xx_eee_init_seq_set(struct phy_device *phydev)
941{
942 const struct reg_val init_eee[] = {
943 {0x0f82, 0x0012b00a},
944 {0x1686, 0x00000004},
945 {0x168c, 0x00d2c46f},
946 {0x17a2, 0x00000620},
947 {0x16a0, 0x00eeffdd},
948 {0x16a6, 0x00071448},
949 {0x16a4, 0x0013132f},
950 {0x16a8, 0x00000000},
951 {0x0ffc, 0x00c0a028},
952 {0x0fe8, 0x0091b06c},
953 {0x0fea, 0x00041600},
954 {0x0f80, 0x00000af4},
955 {0x0fec, 0x00901809},
956 {0x0fee, 0x0000a6a1},
957 {0x0ffe, 0x00b01007},
958 {0x16b0, 0x00eeff00},
959 {0x16b2, 0x00007000},
960 {0x16b4, 0x00000814},
961 };
962 unsigned int i;
963 int oldpage;
964
965 mutex_lock(&phydev->lock);
966 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
967 if (oldpage < 0)
968 goto out_unlock;
969
970 for (i = 0; i < ARRAY_SIZE(init_eee); i++)
971 vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);
972
973out_unlock:
974 oldpage = phy_restore_page(phydev, oldpage, oldpage);
975 mutex_unlock(&phydev->lock);
976
977 return oldpage;
978}
979
Quentin Schulza5afc162018-10-08 12:14:42 +0200980/* phydev->bus->mdio_lock should be locked when using this function */
981static int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
982{
983 struct vsc8531_private *priv = phydev->priv;
984
985 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
986 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
987 dump_stack();
988 }
989
990 return __mdiobus_write(phydev->mdio.bus, priv->base_addr, regnum, val);
991}
992
993/* phydev->bus->mdio_lock should be locked when using this function */
994static int phy_base_read(struct phy_device *phydev, u32 regnum)
995{
996 struct vsc8531_private *priv = phydev->priv;
997
998 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
999 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
1000 dump_stack();
1001 }
1002
1003 return __mdiobus_read(phydev->mdio.bus, priv->base_addr, regnum);
1004}
1005
1006/* bus->mdio_lock should be locked when using this function */
1007static void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val)
1008{
1009 phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
1010 phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
1011 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
1012}
1013
1014/* bus->mdio_lock should be locked when using this function */
1015static int vsc8584_cmd(struct phy_device *phydev, u16 val)
1016{
1017 unsigned long deadline;
1018 u16 reg_val;
1019
1020 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1021 MSCC_PHY_PAGE_EXTENDED_GPIO);
1022
1023 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val);
1024
1025 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
1026 do {
1027 reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD);
1028 } while (time_before(jiffies, deadline) &&
1029 (reg_val & PROC_CMD_NCOMPLETED) &&
1030 !(reg_val & PROC_CMD_FAILED));
1031
1032 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1033
1034 if (reg_val & PROC_CMD_FAILED)
1035 return -EIO;
1036
1037 if (reg_val & PROC_CMD_NCOMPLETED)
1038 return -ETIMEDOUT;
1039
1040 return 0;
1041}
1042
1043/* bus->mdio_lock should be locked when using this function */
1044static int vsc8584_micro_deassert_reset(struct phy_device *phydev,
1045 bool patch_en)
1046{
1047 u32 enable, release;
1048
1049 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1050 MSCC_PHY_PAGE_EXTENDED_GPIO);
1051
1052 enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
1053 release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
1054 MICRO_CLK_EN;
1055
1056 if (patch_en) {
1057 enable |= MICRO_PATCH_EN;
1058 release |= MICRO_PATCH_EN;
1059
1060 /* Clear all patches */
1061 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
1062 }
1063
1064 /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock
1065 * override and addr. auto-incr; operate at 125 MHz
1066 */
1067 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable);
1068 /* Release 8051 Micro SW reset */
1069 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release);
1070
1071 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1072
1073 return 0;
1074}
1075
1076/* bus->mdio_lock should be locked when using this function */
1077static int vsc8584_micro_assert_reset(struct phy_device *phydev)
1078{
1079 int ret;
1080 u16 reg;
1081
1082 ret = vsc8584_cmd(phydev, PROC_CMD_NOP);
1083 if (ret)
1084 return ret;
1085
1086 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1087 MSCC_PHY_PAGE_EXTENDED_GPIO);
1088
1089 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1090 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
1091 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1092
1093 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b);
1094 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b);
1095
1096 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1097 reg |= EN_PATCH_RAM_TRAP_ADDR(4);
1098 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1099
1100 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
1101
1102 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
1103 reg &= ~MICRO_NSOFT_RESET;
1104 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg);
1105
1106 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF |
1107 PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF |
1108 PROC_CMD_READ);
1109
1110 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1111 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
1112 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
1113
1114 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1115
1116 return 0;
1117}
1118
1119/* bus->mdio_lock should be locked when using this function */
1120static int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size,
1121 u16 *crc)
1122{
1123 int ret;
1124
1125 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1126
1127 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start);
1128 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size);
1129
1130 /* Start Micro command */
1131 ret = vsc8584_cmd(phydev, PROC_CMD_CRC16);
1132 if (ret)
1133 goto out;
1134
1135 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1136
1137 *crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
1138
1139out:
1140 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1141
1142 return ret;
1143}
1144
1145/* bus->mdio_lock should be locked when using this function */
1146static int vsc8584_patch_fw(struct phy_device *phydev,
1147 const struct firmware *fw)
1148{
1149 int i, ret;
1150
1151 ret = vsc8584_micro_assert_reset(phydev);
1152 if (ret) {
1153 dev_err(&phydev->mdio.dev,
1154 "%s: failed to assert reset of micro\n", __func__);
1155 return ret;
1156 }
1157
1158 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1159 MSCC_PHY_PAGE_EXTENDED_GPIO);
1160
1161 /* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
1162 * Disable the 8051 Micro clock
1163 */
1164 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM |
1165 AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN |
1166 MICRO_CLK_DIVIDE(2));
1167 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN |
1168 INT_MEM_DATA(2));
1169 phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000);
1170
1171 for (i = 0; i < fw->size; i++)
1172 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM |
1173 INT_MEM_WRITE_EN | fw->data[i]);
1174
1175 /* Clear internal memory access */
1176 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
1177
1178 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1179
1180 return 0;
1181}
1182
1183/* bus->mdio_lock should be locked when using this function */
Quentin Schulz00d70d82018-10-08 12:14:43 +02001184static bool vsc8574_is_serdes_init(struct phy_device *phydev)
1185{
1186 u16 reg;
1187 bool ret;
1188
1189 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1190 MSCC_PHY_PAGE_EXTENDED_GPIO);
1191
1192 reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));
1193 if (reg != 0x3eb7) {
1194 ret = false;
1195 goto out;
1196 }
1197
1198 reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));
1199 if (reg != 0x4012) {
1200 ret = false;
1201 goto out;
1202 }
1203
1204 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
1205 if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
1206 ret = false;
1207 goto out;
1208 }
1209
1210 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
1211 if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
1212 MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
1213 ret = false;
1214 goto out;
1215 }
1216
1217 ret = true;
1218out:
1219 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1220
1221 return ret;
1222}
1223
1224/* bus->mdio_lock should be locked when using this function */
1225static int vsc8574_config_pre_init(struct phy_device *phydev)
1226{
1227 const struct reg_val pre_init1[] = {
1228 {0x0fae, 0x000401bd},
1229 {0x0fac, 0x000f000f},
1230 {0x17a0, 0x00a0f147},
1231 {0x0fe4, 0x00052f54},
1232 {0x1792, 0x0027303d},
1233 {0x07fe, 0x00000704},
1234 {0x0fe0, 0x00060150},
1235 {0x0f82, 0x0012b00a},
1236 {0x0f80, 0x00000d74},
1237 {0x02e0, 0x00000012},
1238 {0x03a2, 0x00050208},
1239 {0x03b2, 0x00009186},
1240 {0x0fb0, 0x000e3700},
1241 {0x1688, 0x00049f81},
1242 {0x0fd2, 0x0000ffff},
1243 {0x168a, 0x00039fa2},
1244 {0x1690, 0x0020640b},
1245 {0x0258, 0x00002220},
1246 {0x025a, 0x00002a20},
1247 {0x025c, 0x00003060},
1248 {0x025e, 0x00003fa0},
1249 {0x03a6, 0x0000e0f0},
1250 {0x0f92, 0x00001489},
1251 {0x16a2, 0x00007000},
1252 {0x16a6, 0x00071448},
1253 {0x16a0, 0x00eeffdd},
1254 {0x0fe8, 0x0091b06c},
1255 {0x0fea, 0x00041600},
1256 {0x16b0, 0x00eeff00},
1257 {0x16b2, 0x00007000},
1258 {0x16b4, 0x00000814},
1259 {0x0f90, 0x00688980},
1260 {0x03a4, 0x0000d8f0},
1261 {0x0fc0, 0x00000400},
1262 {0x07fa, 0x0050100f},
1263 {0x0796, 0x00000003},
1264 {0x07f8, 0x00c3ff98},
1265 {0x0fa4, 0x0018292a},
1266 {0x168c, 0x00d2c46f},
1267 {0x17a2, 0x00000620},
1268 {0x16a4, 0x0013132f},
1269 {0x16a8, 0x00000000},
1270 {0x0ffc, 0x00c0a028},
1271 {0x0fec, 0x00901c09},
1272 {0x0fee, 0x0004a6a1},
1273 {0x0ffe, 0x00b01807},
1274 };
1275 const struct reg_val pre_init2[] = {
1276 {0x0486, 0x0008a518},
1277 {0x0488, 0x006dc696},
1278 {0x048a, 0x00000912},
1279 {0x048e, 0x00000db6},
1280 {0x049c, 0x00596596},
1281 {0x049e, 0x00000514},
1282 {0x04a2, 0x00410280},
1283 {0x04a4, 0x00000000},
1284 {0x04a6, 0x00000000},
1285 {0x04a8, 0x00000000},
1286 {0x04aa, 0x00000000},
1287 {0x04ae, 0x007df7dd},
1288 {0x04b0, 0x006d95d4},
1289 {0x04b2, 0x00492410},
1290 };
1291 struct device *dev = &phydev->mdio.dev;
1292 const struct firmware *fw;
1293 unsigned int i;
1294 u16 crc, reg;
1295 bool serdes_init;
1296 int ret;
1297
1298 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1299
1300 /* all writes below are broadcasted to all PHYs in the same package */
1301 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1302 reg |= SMI_BROADCAST_WR_EN;
1303 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1304
1305 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
1306
1307 /* The below register writes are tweaking analog and electrical
1308 * configuration that were determined through characterization by PHY
1309 * engineers. These don't mean anything more than "these are the best
1310 * values".
1311 */
1312 phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
1313
1314 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1315
1316 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);
1317 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);
1318 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);
1319 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);
1320
1321 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1322 reg |= 0x8000;
1323 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1324
1325 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1326
1327 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1328 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1329
1330 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1331
1332 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
1333
1334 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1335
1336 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
1337 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
1338
1339 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1340
1341 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1342 reg &= ~0x8000;
1343 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1344
1345 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1346
1347 /* end of write broadcasting */
1348 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1349 reg &= ~SMI_BROADCAST_WR_EN;
1350 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1351
1352 ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);
1353 if (ret) {
1354 dev_err(dev, "failed to load firmware %s, ret: %d\n",
1355 MSCC_VSC8574_REVB_INT8051_FW, ret);
1356 return ret;
1357 }
1358
1359 /* Add one byte to size for the one added by the patch_fw function */
1360 ret = vsc8584_get_fw_crc(phydev,
1361 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
1362 fw->size + 1, &crc);
1363 if (ret)
1364 goto out;
1365
1366 if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
1367 serdes_init = vsc8574_is_serdes_init(phydev);
1368
1369 if (!serdes_init) {
1370 ret = vsc8584_micro_assert_reset(phydev);
1371 if (ret) {
1372 dev_err(dev,
1373 "%s: failed to assert reset of micro\n",
1374 __func__);
Gustavo A. R. Silva47d20212018-10-16 19:37:35 +02001375 goto out;
Quentin Schulz00d70d82018-10-08 12:14:43 +02001376 }
1377 }
1378 } else {
1379 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
1380
1381 serdes_init = false;
1382
1383 if (vsc8584_patch_fw(phydev, fw))
1384 dev_warn(dev,
1385 "failed to patch FW, expect non-optimal device\n");
1386 }
1387
1388 if (!serdes_init) {
1389 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1390 MSCC_PHY_PAGE_EXTENDED_GPIO);
1391
1392 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);
1393 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);
1394 phy_base_write(phydev, MSCC_INT_MEM_CNTL,
1395 EN_PATCH_RAM_TRAP_ADDR(1));
1396
1397 vsc8584_micro_deassert_reset(phydev, false);
1398
1399 /* Add one byte to size for the one added by the patch_fw
1400 * function
1401 */
1402 ret = vsc8584_get_fw_crc(phydev,
1403 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
1404 fw->size + 1, &crc);
1405 if (ret)
1406 goto out;
1407
1408 if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
1409 dev_warn(dev,
1410 "FW CRC after patching is not the expected one, expect non-optimal device\n");
1411 }
1412
1413 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1414 MSCC_PHY_PAGE_EXTENDED_GPIO);
1415
1416 ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |
1417 PROC_CMD_PHY_INIT);
1418
1419out:
1420 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1421
1422 release_firmware(fw);
1423
1424 return ret;
1425}
1426
1427/* bus->mdio_lock should be locked when using this function */
Quentin Schulza5afc162018-10-08 12:14:42 +02001428static int vsc8584_config_pre_init(struct phy_device *phydev)
1429{
1430 const struct reg_val pre_init1[] = {
1431 {0x07fa, 0x0050100f},
1432 {0x1688, 0x00049f81},
1433 {0x0f90, 0x00688980},
1434 {0x03a4, 0x0000d8f0},
1435 {0x0fc0, 0x00000400},
1436 {0x0f82, 0x0012b002},
1437 {0x1686, 0x00000004},
1438 {0x168c, 0x00d2c46f},
1439 {0x17a2, 0x00000620},
1440 {0x16a0, 0x00eeffdd},
1441 {0x16a6, 0x00071448},
1442 {0x16a4, 0x0013132f},
1443 {0x16a8, 0x00000000},
1444 {0x0ffc, 0x00c0a028},
1445 {0x0fe8, 0x0091b06c},
1446 {0x0fea, 0x00041600},
1447 {0x0f80, 0x00fffaff},
1448 {0x0fec, 0x00901809},
1449 {0x0ffe, 0x00b01007},
1450 {0x16b0, 0x00eeff00},
1451 {0x16b2, 0x00007000},
1452 {0x16b4, 0x00000814},
1453 };
1454 const struct reg_val pre_init2[] = {
1455 {0x0486, 0x0008a518},
1456 {0x0488, 0x006dc696},
1457 {0x048a, 0x00000912},
1458 };
1459 const struct firmware *fw;
1460 struct device *dev = &phydev->mdio.dev;
1461 unsigned int i;
1462 u16 crc, reg;
1463 int ret;
1464
1465 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1466
1467 /* all writes below are broadcasted to all PHYs in the same package */
1468 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1469 reg |= SMI_BROADCAST_WR_EN;
1470 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1471
1472 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
1473
1474 reg = phy_base_read(phydev, MSCC_PHY_BYPASS_CONTROL);
1475 reg |= PARALLEL_DET_IGNORE_ADVERTISED;
1476 phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg);
1477
1478 /* The below register writes are tweaking analog and electrical
1479 * configuration that were determined through characterization by PHY
1480 * engineers. These don't mean anything more than "these are the best
1481 * values".
1482 */
1483 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
1484
1485 phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000);
1486
1487 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1488
1489 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20);
1490
1491 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1492 reg |= 0x8000;
1493 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1494
1495 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1496
1497 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4));
1498
1499 reg = phy_base_read(phydev, MSCC_PHY_TR_MSB);
1500 reg &= ~0x007f;
1501 reg |= 0x0019;
1502 phy_base_write(phydev, MSCC_PHY_TR_MSB, reg);
1503
1504 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4));
1505
1506 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1507 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1508
1509 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1510
1511 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
1512
1513 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1514
1515 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
1516 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
1517
1518 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1519
1520 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1521 reg &= ~0x8000;
1522 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1523
1524 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1525
1526 /* end of write broadcasting */
1527 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1528 reg &= ~SMI_BROADCAST_WR_EN;
1529 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1530
1531 ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev);
1532 if (ret) {
1533 dev_err(dev, "failed to load firmware %s, ret: %d\n",
1534 MSCC_VSC8584_REVB_INT8051_FW, ret);
1535 return ret;
1536 }
1537
1538 /* Add one byte to size for the one added by the patch_fw function */
1539 ret = vsc8584_get_fw_crc(phydev,
1540 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
1541 fw->size + 1, &crc);
1542 if (ret)
1543 goto out;
1544
1545 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
1546 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
1547 if (vsc8584_patch_fw(phydev, fw))
1548 dev_warn(dev,
1549 "failed to patch FW, expect non-optimal device\n");
1550 }
1551
1552 vsc8584_micro_deassert_reset(phydev, false);
1553
1554 /* Add one byte to size for the one added by the patch_fw function */
1555 ret = vsc8584_get_fw_crc(phydev,
1556 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
1557 fw->size + 1, &crc);
1558 if (ret)
1559 goto out;
1560
1561 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
1562 dev_warn(dev,
1563 "FW CRC after patching is not the expected one, expect non-optimal device\n");
1564
1565 ret = vsc8584_micro_assert_reset(phydev);
1566 if (ret)
1567 goto out;
1568
1569 vsc8584_micro_deassert_reset(phydev, true);
1570
1571out:
1572 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1573
1574 release_firmware(fw);
1575
1576 return ret;
1577}
1578
1579/* Check if one PHY has already done the init of the parts common to all PHYs
1580 * in the Quad PHY package.
1581 */
1582static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed)
1583{
1584 struct mdio_device **map = phydev->mdio.bus->mdio_map;
1585 struct vsc8531_private *vsc8531;
1586 struct phy_device *phy;
1587 int i, addr;
1588
1589 /* VSC8584 is a Quad PHY */
1590 for (i = 0; i < 4; i++) {
1591 vsc8531 = phydev->priv;
1592
1593 if (reversed)
1594 addr = vsc8531->base_addr - i;
1595 else
1596 addr = vsc8531->base_addr + i;
1597
1598 phy = container_of(map[addr], struct phy_device, mdio);
1599
1600 if ((phy->phy_id & phydev->drv->phy_id_mask) !=
1601 (phydev->drv->phy_id & phydev->drv->phy_id_mask))
1602 continue;
1603
1604 vsc8531 = phy->priv;
1605
1606 if (vsc8531 && vsc8531->pkg_init)
1607 return true;
1608 }
1609
1610 return false;
1611}
1612
1613static int vsc8584_config_init(struct phy_device *phydev)
1614{
1615 struct vsc8531_private *vsc8531 = phydev->priv;
1616 u16 addr, val;
1617 int ret, i;
1618
1619 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1620
1621 mutex_lock(&phydev->mdio.bus->mdio_lock);
1622
1623 __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
1624 MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1625 addr = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
1626 MSCC_PHY_EXT_PHY_CNTL_4);
1627 addr >>= PHY_CNTL_4_ADDR_POS;
1628
1629 val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
1630 MSCC_PHY_ACTIPHY_CNTL);
1631 if (val & PHY_ADDR_REVERSED)
1632 vsc8531->base_addr = phydev->mdio.addr + addr;
1633 else
1634 vsc8531->base_addr = phydev->mdio.addr - addr;
1635
1636 /* Some parts of the init sequence are identical for every PHY in the
1637 * package. Some parts are modifying the GPIO register bank which is a
1638 * set of registers that are affecting all PHYs, a few resetting the
1639 * microprocessor common to all PHYs. The CRC check responsible of the
1640 * checking the firmware within the 8051 microprocessor can only be
1641 * accessed via the PHY whose internal address in the package is 0.
1642 * All PHYs' interrupts mask register has to be zeroed before enabling
1643 * any PHY's interrupt in this register.
1644 * For all these reasons, we need to do the init sequence once and only
1645 * once whatever is the first PHY in the package that is initialized and
1646 * do the correct init sequence for all PHYs that are package-critical
1647 * in this pre-init function.
1648 */
1649 if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
Quentin Schulz00d70d82018-10-08 12:14:43 +02001650 if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
1651 (PHY_ID_VSC8574 & phydev->drv->phy_id_mask))
1652 ret = vsc8574_config_pre_init(phydev);
1653 else if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
1654 (PHY_ID_VSC8584 & phydev->drv->phy_id_mask))
1655 ret = vsc8584_config_pre_init(phydev);
1656 else
1657 ret = -EINVAL;
1658
Quentin Schulza5afc162018-10-08 12:14:42 +02001659 if (ret)
1660 goto err;
1661 }
1662
1663 vsc8531->pkg_init = true;
1664
1665 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1666 MSCC_PHY_PAGE_EXTENDED_GPIO);
1667
1668 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
1669 val &= ~MAC_CFG_MASK;
1670 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1671 val |= MAC_CFG_QSGMII;
1672 else
1673 val |= MAC_CFG_SGMII;
1674
1675 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
1676 if (ret)
1677 goto err;
1678
1679 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
1680 PROC_CMD_READ_MOD_WRITE_PORT;
1681 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1682 val |= PROC_CMD_QSGMII_MAC;
1683 else
1684 val |= PROC_CMD_SGMII_MAC;
1685
1686 ret = vsc8584_cmd(phydev, val);
1687 if (ret)
1688 goto err;
1689
1690 usleep_range(10000, 20000);
1691
1692 /* Disable SerDes for 100Base-FX */
1693 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
1694 PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1695 PROC_CMD_READ_MOD_WRITE_PORT |
1696 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
1697 if (ret)
1698 goto err;
1699
1700 /* Disable SerDes for 1000Base-X */
1701 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
1702 PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1703 PROC_CMD_READ_MOD_WRITE_PORT |
1704 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
1705 if (ret)
1706 goto err;
1707
1708 mutex_unlock(&phydev->mdio.bus->mdio_lock);
1709
1710 phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1711
1712 val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
1713 val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
1714 val |= MEDIA_OP_MODE_COPPER | (VSC8584_MAC_IF_SELECTION_SGMII <<
1715 VSC8584_MAC_IF_SELECTION_POS);
1716 ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);
1717
1718 ret = genphy_soft_reset(phydev);
1719 if (ret)
1720 return ret;
1721
1722 for (i = 0; i < vsc8531->nleds; i++) {
1723 ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
1724 if (ret)
1725 return ret;
1726 }
1727
1728 return genphy_config_init(phydev);
1729
1730err:
1731 mutex_unlock(&phydev->mdio.bus->mdio_lock);
1732 return ret;
1733}
1734
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301735static int vsc85xx_config_init(struct phy_device *phydev)
1736{
Raju Lakkaraju7b98f632018-12-18 14:57:56 +05301737 int rc, i, phy_id;
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301738 struct vsc8531_private *vsc8531 = phydev->priv;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301739
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05301740 rc = vsc85xx_default_config(phydev);
1741 if (rc)
1742 return rc;
Raju Lakkaraju1a211012016-09-19 15:33:54 +05301743
1744 rc = vsc85xx_mac_if_set(phydev, phydev->interface);
1745 if (rc)
1746 return rc;
1747
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02001748 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05301749 if (rc)
1750 return rc;
1751
Raju Lakkaraju7b98f632018-12-18 14:57:56 +05301752 phy_id = phydev->drv->phy_id & phydev->drv->phy_id_mask;
1753 if (PHY_ID_VSC8531 == phy_id || PHY_ID_VSC8541 == phy_id ||
1754 PHY_ID_VSC8530 == phy_id || PHY_ID_VSC8540 == phy_id) {
1755 rc = vsc8531_pre_init_seq_set(phydev);
1756 if (rc)
1757 return rc;
1758 }
1759
Raju Lakkaraju96dae012018-10-08 12:07:25 +02001760 rc = vsc85xx_eee_init_seq_set(phydev);
1761 if (rc)
1762 return rc;
1763
Quentin Schulz11bfdab2018-09-03 10:48:47 +02001764 for (i = 0; i < vsc8531->nleds; i++) {
1765 rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
1766 if (rc)
1767 return rc;
1768 }
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +05301769
Quentin Schulz629ea0f2018-10-08 12:07:28 +02001770 return genphy_config_init(phydev);
Raju Lakkarajud50736a2016-08-05 17:54:21 +05301771}
1772
Quentin Schulza5afc162018-10-08 12:14:42 +02001773static int vsc8584_did_interrupt(struct phy_device *phydev)
1774{
1775 int rc = 0;
1776
1777 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
1778 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
1779
1780 return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
1781}
1782
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +00001783static int vsc8514_config_pre_init(struct phy_device *phydev)
1784{
1785 /* These are the settings to override the silicon default
1786 * values to handle hardware performance of PHY. They
1787 * are set at Power-On state and remain until PHY Reset.
1788 */
1789 const struct reg_val pre_init1[] = {
1790 {0x0f90, 0x00688980},
1791 {0x0786, 0x00000003},
1792 {0x07fa, 0x0050100f},
1793 {0x0f82, 0x0012b002},
1794 {0x1686, 0x00000004},
1795 {0x168c, 0x00d2c46f},
1796 {0x17a2, 0x00000620},
1797 {0x16a0, 0x00eeffdd},
1798 {0x16a6, 0x00071448},
1799 {0x16a4, 0x0013132f},
1800 {0x16a8, 0x00000000},
1801 {0x0ffc, 0x00c0a028},
1802 {0x0fe8, 0x0091b06c},
1803 {0x0fea, 0x00041600},
1804 {0x0f80, 0x00fffaff},
1805 {0x0fec, 0x00901809},
1806 {0x0ffe, 0x00b01007},
1807 {0x16b0, 0x00eeff00},
1808 {0x16b2, 0x00007000},
1809 {0x16b4, 0x00000814},
1810 };
1811 unsigned int i;
1812 u16 reg;
1813
1814 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1815
1816 /* all writes below are broadcasted to all PHYs in the same package */
1817 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1818 reg |= SMI_BROADCAST_WR_EN;
1819 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1820
1821 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1822
1823 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1824 reg |= BIT(15);
1825 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1826
1827 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1828
1829 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
1830 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
1831
1832 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
1833
1834 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
1835 reg &= ~BIT(15);
1836 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
1837
1838 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1839
1840 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
1841 reg &= ~SMI_BROADCAST_WR_EN;
1842 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
1843
1844 return 0;
1845}
1846
1847static u32 vsc85xx_csr_ctrl_phy_read(struct phy_device *phydev,
1848 u32 target, u32 reg)
1849{
1850 unsigned long deadline;
1851 u32 val, val_l, val_h;
1852
1853 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);
1854
1855 /* CSR registers are grouped under different Target IDs.
1856 * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and
1857 * MSCC_EXT_PAGE_CSR_CNTL_19 registers.
1858 * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20
1859 * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.
1860 */
1861
1862 /* Setup the Target ID */
1863 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,
1864 MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));
1865
1866 /* Trigger CSR Action - Read into the CSR's */
1867 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,
1868 MSCC_PHY_CSR_CNTL_19_CMD | MSCC_PHY_CSR_CNTL_19_READ |
1869 MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |
1870 MSCC_PHY_CSR_CNTL_19_TARGET(target & 0x3));
1871
1872 /* Wait for register access*/
1873 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
1874 do {
1875 usleep_range(500, 1000);
1876 val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);
1877 } while (time_before(jiffies, deadline) &&
1878 !(val & MSCC_PHY_CSR_CNTL_19_CMD));
1879
1880 if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))
1881 return 0xffffffff;
1882
1883 /* Read the Least Significant Word (LSW) (17) */
1884 val_l = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_17);
1885
1886 /* Read the Most Significant Word (MSW) (18) */
1887 val_h = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_18);
1888
1889 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1890 MSCC_PHY_PAGE_STANDARD);
1891
1892 return (val_h << 16) | val_l;
1893}
1894
1895static int vsc85xx_csr_ctrl_phy_write(struct phy_device *phydev,
1896 u32 target, u32 reg, u32 val)
1897{
1898 unsigned long deadline;
1899
1900 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);
1901
1902 /* CSR registers are grouped under different Target IDs.
1903 * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and
1904 * MSCC_EXT_PAGE_CSR_CNTL_19 registers.
1905 * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20
1906 * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.
1907 */
1908
1909 /* Setup the Target ID */
1910 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,
1911 MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));
1912
1913 /* Write the Least Significant Word (LSW) (17) */
1914 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_17, (u16)val);
1915
1916 /* Write the Most Significant Word (MSW) (18) */
1917 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_18, (u16)(val >> 16));
1918
1919 /* Trigger CSR Action - Write into the CSR's */
1920 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,
1921 MSCC_PHY_CSR_CNTL_19_CMD |
1922 MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |
1923 MSCC_PHY_CSR_CNTL_19_TARGET(target & 0x3));
1924
1925 /* Wait for register access */
1926 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
1927 do {
1928 usleep_range(500, 1000);
1929 val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);
1930 } while (time_before(jiffies, deadline) &&
1931 !(val & MSCC_PHY_CSR_CNTL_19_CMD));
1932
1933 if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))
1934 return -ETIMEDOUT;
1935
1936 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
1937 MSCC_PHY_PAGE_STANDARD);
1938
1939 return 0;
1940}
1941
1942static int __phy_write_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb,
1943 u32 op)
1944{
1945 unsigned long deadline;
1946 u32 val;
1947 int ret;
1948
1949 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET, reg,
1950 op | (1 << mcb));
1951 if (ret)
1952 return -EINVAL;
1953
1954 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
1955 do {
1956 usleep_range(500, 1000);
1957 val = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET, reg);
1958
1959 if (val == 0xffffffff)
1960 return -EIO;
1961
1962 } while (time_before(jiffies, deadline) && (val & op));
1963
1964 if (val & op)
1965 return -ETIMEDOUT;
1966
1967 return 0;
1968}
1969
1970/* Trigger a read to the spcified MCB */
1971static int phy_update_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
1972{
1973 return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_READ);
1974}
1975
1976/* Trigger a write to the spcified MCB */
1977static int phy_commit_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
1978{
1979 return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_WRITE);
1980}
1981
1982static int vsc8514_config_init(struct phy_device *phydev)
1983{
1984 struct vsc8531_private *vsc8531 = phydev->priv;
1985 unsigned long deadline;
1986 u16 val, addr;
1987 int ret, i;
1988 u32 reg;
1989
1990 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1991
1992 mutex_lock(&phydev->mdio.bus->mdio_lock);
1993
1994 __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
1995
1996 addr = __phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_4);
1997 addr >>= PHY_CNTL_4_ADDR_POS;
1998
1999 val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
2000
2001 if (val & PHY_ADDR_REVERSED)
2002 vsc8531->base_addr = phydev->mdio.addr + addr;
2003 else
2004 vsc8531->base_addr = phydev->mdio.addr - addr;
2005
2006 /* Some parts of the init sequence are identical for every PHY in the
2007 * package. Some parts are modifying the GPIO register bank which is a
2008 * set of registers that are affecting all PHYs, a few resetting the
2009 * microprocessor common to all PHYs.
2010 * All PHYs' interrupts mask register has to be zeroed before enabling
2011 * any PHY's interrupt in this register.
2012 * For all these reasons, we need to do the init sequence once and only
2013 * once whatever is the first PHY in the package that is initialized and
2014 * do the correct init sequence for all PHYs that are package-critical
2015 * in this pre-init function.
2016 */
2017 if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0))
2018 vsc8514_config_pre_init(phydev);
2019
2020 vsc8531->pkg_init = true;
2021
2022 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
2023 MSCC_PHY_PAGE_EXTENDED_GPIO);
2024
2025 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
2026
2027 val &= ~MAC_CFG_MASK;
2028 val |= MAC_CFG_QSGMII;
2029 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
2030
2031 if (ret)
2032 goto err;
2033
2034 ret = vsc8584_cmd(phydev,
2035 PROC_CMD_MCB_ACCESS_MAC_CONF |
2036 PROC_CMD_RST_CONF_PORT |
2037 PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_QSGMII_MAC);
2038 if (ret)
2039 goto err;
2040
2041 /* 6g mcb */
2042 phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
2043 /* lcpll mcb */
2044 phy_update_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
2045 /* pll5gcfg0 */
2046 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
2047 PHY_S6G_PLL5G_CFG0, 0x7036f145);
2048 if (ret)
2049 goto err;
2050
2051 phy_commit_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
2052 /* pllcfg */
2053 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
2054 PHY_S6G_PLL_CFG,
2055 (3 << PHY_S6G_PLL_ENA_OFFS_POS) |
2056 (120 << PHY_S6G_PLL_FSM_CTRL_DATA_POS)
2057 | (0 << PHY_S6G_PLL_FSM_ENA_POS));
2058 if (ret)
2059 goto err;
2060
2061 /* commoncfg */
2062 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
2063 PHY_S6G_COMMON_CFG,
2064 (0 << PHY_S6G_SYS_RST_POS) |
2065 (0 << PHY_S6G_ENA_LANE_POS) |
2066 (0 << PHY_S6G_ENA_LOOP_POS) |
2067 (0 << PHY_S6G_QRATE_POS) |
2068 (3 << PHY_S6G_IF_MODE_POS));
2069 if (ret)
2070 goto err;
2071
2072 /* misccfg */
2073 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
2074 PHY_S6G_MISC_CFG, 1);
2075 if (ret)
2076 goto err;
2077
2078 /* gpcfg */
2079 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
2080 PHY_S6G_GPC_CFG, 768);
2081 if (ret)
2082 goto err;
2083
2084 phy_commit_mcb_s6g(phydev, PHY_S6G_DFT_CFG2, 0);
2085
2086 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
2087 do {
2088 usleep_range(500, 1000);
2089 phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG,
2090 0); /* read 6G MCB into CSRs */
2091 reg = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET,
2092 PHY_S6G_PLL_STATUS);
2093 if (reg == 0xffffffff) {
2094 mutex_unlock(&phydev->mdio.bus->mdio_lock);
2095 return -EIO;
2096 }
2097
2098 } while (time_before(jiffies, deadline) && (reg & BIT(12)));
2099
2100 if (reg & BIT(12)) {
2101 mutex_unlock(&phydev->mdio.bus->mdio_lock);
2102 return -ETIMEDOUT;
2103 }
2104
2105 /* misccfg */
2106 ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
2107 PHY_S6G_MISC_CFG, 0);
2108 if (ret)
2109 goto err;
2110
2111 phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
2112
2113 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
2114 do {
2115 usleep_range(500, 1000);
2116 phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG,
2117 0); /* read 6G MCB into CSRs */
2118 reg = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET,
2119 PHY_S6G_IB_STATUS0);
2120 if (reg == 0xffffffff) {
2121 mutex_unlock(&phydev->mdio.bus->mdio_lock);
2122 return -EIO;
2123 }
2124
2125 } while (time_before(jiffies, deadline) && !(reg & BIT(8)));
2126
2127 if (!(reg & BIT(8))) {
2128 mutex_unlock(&phydev->mdio.bus->mdio_lock);
2129 return -ETIMEDOUT;
2130 }
2131
2132 mutex_unlock(&phydev->mdio.bus->mdio_lock);
2133
2134 ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
2135
2136 if (ret)
2137 return ret;
2138
2139 ret = phy_modify(phydev, MSCC_PHY_EXT_PHY_CNTL_1, MEDIA_OP_MODE_MASK,
2140 MEDIA_OP_MODE_COPPER);
2141
2142 if (ret)
2143 return ret;
2144
2145 ret = genphy_soft_reset(phydev);
2146
2147 if (ret)
2148 return ret;
2149
2150 for (i = 0; i < vsc8531->nleds; i++) {
2151 ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
2152 if (ret)
2153 return ret;
2154 }
2155
2156 return ret;
2157
2158err:
2159 mutex_unlock(&phydev->mdio.bus->mdio_lock);
2160 return ret;
2161}
2162
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302163static int vsc85xx_ack_interrupt(struct phy_device *phydev)
2164{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302165 int rc = 0;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302166
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302167 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
2168 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302169
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302170 return (rc < 0) ? rc : 0;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302171}
2172
2173static int vsc85xx_config_intr(struct phy_device *phydev)
2174{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302175 int rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302176
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302177 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
2178 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
2179 MII_VSC85XX_INT_MASK_MASK);
2180 } else {
2181 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
2182 if (rc < 0)
2183 return rc;
2184 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
2185 }
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302186
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302187 return rc;
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302188}
2189
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302190static int vsc85xx_config_aneg(struct phy_device *phydev)
2191{
2192 int rc;
2193
2194 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
2195 if (rc < 0)
2196 return rc;
2197
2198 return genphy_config_aneg(phydev);
2199}
2200
2201static int vsc85xx_read_status(struct phy_device *phydev)
2202{
2203 int rc;
2204
2205 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
2206 if (rc < 0)
2207 return rc;
2208
2209 return genphy_read_status(phydev);
2210}
2211
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +00002212static int vsc8514_probe(struct phy_device *phydev)
2213{
2214 struct vsc8531_private *vsc8531;
2215 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
2216 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
2217 VSC8531_DUPLEX_COLLISION};
2218
2219 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
2220 if (!vsc8531)
2221 return -ENOMEM;
2222
2223 phydev->priv = vsc8531;
2224
2225 vsc8531->nleds = 4;
2226 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
2227 vsc8531->hw_stats = vsc85xx_hw_stats;
2228 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
Andreas Schwabf9720372019-07-24 17:32:57 +02002229 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
2230 sizeof(u64), GFP_KERNEL);
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +00002231 if (!vsc8531->stats)
2232 return -ENOMEM;
2233
2234 return vsc85xx_dt_led_modes_get(phydev, default_mode);
2235}
2236
Quentin Schulz00d70d82018-10-08 12:14:43 +02002237static int vsc8574_probe(struct phy_device *phydev)
2238{
2239 struct vsc8531_private *vsc8531;
2240 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
2241 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
2242 VSC8531_DUPLEX_COLLISION};
2243
2244 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
2245 if (!vsc8531)
2246 return -ENOMEM;
2247
2248 phydev->priv = vsc8531;
2249
2250 vsc8531->nleds = 4;
2251 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
2252 vsc8531->hw_stats = vsc8584_hw_stats;
2253 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
Andreas Schwabf9720372019-07-24 17:32:57 +02002254 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
2255 sizeof(u64), GFP_KERNEL);
Quentin Schulz00d70d82018-10-08 12:14:43 +02002256 if (!vsc8531->stats)
2257 return -ENOMEM;
2258
2259 return vsc85xx_dt_led_modes_get(phydev, default_mode);
2260}
2261
Quentin Schulza5afc162018-10-08 12:14:42 +02002262static int vsc8584_probe(struct phy_device *phydev)
2263{
2264 struct vsc8531_private *vsc8531;
2265 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
2266 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
2267 VSC8531_DUPLEX_COLLISION};
2268
2269 if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
2270 dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n");
2271 return -ENOTSUPP;
2272 }
2273
2274 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
2275 if (!vsc8531)
2276 return -ENOMEM;
2277
2278 phydev->priv = vsc8531;
2279
2280 vsc8531->nleds = 4;
2281 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
2282 vsc8531->hw_stats = vsc8584_hw_stats;
2283 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
Andreas Schwabf9720372019-07-24 17:32:57 +02002284 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
2285 sizeof(u64), GFP_KERNEL);
Quentin Schulza5afc162018-10-08 12:14:42 +02002286 if (!vsc8531->stats)
2287 return -ENOMEM;
2288
2289 return vsc85xx_dt_led_modes_get(phydev, default_mode);
2290}
2291
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05302292static int vsc85xx_probe(struct phy_device *phydev)
2293{
2294 struct vsc8531_private *vsc8531;
Raju Lakkaraju04d8a0a2017-02-07 19:10:26 +05302295 int rate_magic;
Quentin Schulz5ff8e1f2018-09-03 10:48:51 +02002296 u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
Quentin Schulz11bfdab2018-09-03 10:48:47 +02002297 VSC8531_LINK_100_ACTIVITY};
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05302298
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02002299 rate_magic = vsc85xx_edge_rate_magic_get(phydev);
2300 if (rate_magic < 0)
2301 return rate_magic;
2302
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05302303 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
2304 if (!vsc8531)
2305 return -ENOMEM;
2306
2307 phydev->priv = vsc8531;
2308
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02002309 vsc8531->rate_magic = rate_magic;
Quentin Schulz11bfdab2018-09-03 10:48:47 +02002310 vsc8531->nleds = 2;
Quentin Schulz0969aba2018-09-03 10:48:48 +02002311 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02002312 vsc8531->hw_stats = vsc85xx_hw_stats;
2313 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
Andreas Schwabf9720372019-07-24 17:32:57 +02002314 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
2315 sizeof(u64), GFP_KERNEL);
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02002316 if (!vsc8531->stats)
2317 return -ENOMEM;
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02002318
Quentin Schulz11bfdab2018-09-03 10:48:47 +02002319 return vsc85xx_dt_led_modes_get(phydev, default_mode);
Raju Lakkarajua4cc96d2016-10-03 12:53:13 +05302320}
2321
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302322/* Microsemi VSC85xx PHYs */
2323static struct phy_driver vsc85xx_driver[] = {
2324{
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +00002325 .phy_id = PHY_ID_VSC8514,
2326 .name = "Microsemi GE VSC8514 SyncE",
2327 .phy_id_mask = 0xfffffff0,
2328 .soft_reset = &genphy_soft_reset,
2329 .config_init = &vsc8514_config_init,
2330 .config_aneg = &vsc85xx_config_aneg,
2331 .read_status = &vsc85xx_read_status,
2332 .ack_interrupt = &vsc85xx_ack_interrupt,
2333 .config_intr = &vsc85xx_config_intr,
2334 .suspend = &genphy_suspend,
2335 .resume = &genphy_resume,
2336 .probe = &vsc8514_probe,
2337 .set_wol = &vsc85xx_wol_set,
2338 .get_wol = &vsc85xx_wol_get,
2339 .get_tunable = &vsc85xx_get_tunable,
2340 .set_tunable = &vsc85xx_set_tunable,
2341 .read_page = &vsc85xx_phy_read_page,
2342 .write_page = &vsc85xx_phy_write_page,
2343 .get_sset_count = &vsc85xx_get_sset_count,
2344 .get_strings = &vsc85xx_get_strings,
2345 .get_stats = &vsc85xx_get_stats,
2346},
2347{
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002348 .phy_id = PHY_ID_VSC8530,
2349 .name = "Microsemi FE VSC8530",
2350 .phy_id_mask = 0xfffffff0,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002351 /* PHY_BASIC_FEATURES */
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002352 .soft_reset = &genphy_soft_reset,
2353 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302354 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002355 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302356 .read_status = &vsc85xx_read_status,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002357 .ack_interrupt = &vsc85xx_ack_interrupt,
2358 .config_intr = &vsc85xx_config_intr,
2359 .suspend = &genphy_suspend,
2360 .resume = &genphy_resume,
2361 .probe = &vsc85xx_probe,
2362 .set_wol = &vsc85xx_wol_set,
2363 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01002364 .get_tunable = &vsc85xx_get_tunable,
2365 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02002366 .read_page = &vsc85xx_phy_read_page,
2367 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02002368 .get_sset_count = &vsc85xx_get_sset_count,
2369 .get_strings = &vsc85xx_get_strings,
2370 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002371},
2372{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302373 .phy_id = PHY_ID_VSC8531,
2374 .name = "Microsemi VSC8531",
2375 .phy_id_mask = 0xfffffff0,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002376 /* PHY_GBIT_FEATURES */
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302377 .soft_reset = &genphy_soft_reset,
2378 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302379 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302380 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302381 .read_status = &vsc85xx_read_status,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302382 .ack_interrupt = &vsc85xx_ack_interrupt,
2383 .config_intr = &vsc85xx_config_intr,
2384 .suspend = &genphy_suspend,
2385 .resume = &genphy_resume,
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02002386 .probe = &vsc85xx_probe,
2387 .set_wol = &vsc85xx_wol_set,
2388 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01002389 .get_tunable = &vsc85xx_get_tunable,
2390 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02002391 .read_page = &vsc85xx_phy_read_page,
2392 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02002393 .get_sset_count = &vsc85xx_get_sset_count,
2394 .get_strings = &vsc85xx_get_strings,
2395 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302396},
2397{
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002398 .phy_id = PHY_ID_VSC8540,
2399 .name = "Microsemi FE VSC8540 SyncE",
2400 .phy_id_mask = 0xfffffff0,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002401 /* PHY_BASIC_FEATURES */
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002402 .soft_reset = &genphy_soft_reset,
2403 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302404 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002405 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302406 .read_status = &vsc85xx_read_status,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002407 .ack_interrupt = &vsc85xx_ack_interrupt,
2408 .config_intr = &vsc85xx_config_intr,
2409 .suspend = &genphy_suspend,
2410 .resume = &genphy_resume,
2411 .probe = &vsc85xx_probe,
2412 .set_wol = &vsc85xx_wol_set,
2413 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01002414 .get_tunable = &vsc85xx_get_tunable,
2415 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02002416 .read_page = &vsc85xx_phy_read_page,
2417 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02002418 .get_sset_count = &vsc85xx_get_sset_count,
2419 .get_strings = &vsc85xx_get_strings,
2420 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002421},
2422{
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302423 .phy_id = PHY_ID_VSC8541,
2424 .name = "Microsemi VSC8541 SyncE",
2425 .phy_id_mask = 0xfffffff0,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002426 /* PHY_GBIT_FEATURES */
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302427 .soft_reset = &genphy_soft_reset,
2428 .config_init = &vsc85xx_config_init,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302429 .config_aneg = &vsc85xx_config_aneg,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302430 .aneg_done = &genphy_aneg_done,
Raju Lakkaraju233275e2016-11-29 15:16:48 +05302431 .read_status = &vsc85xx_read_status,
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302432 .ack_interrupt = &vsc85xx_ack_interrupt,
2433 .config_intr = &vsc85xx_config_intr,
2434 .suspend = &genphy_suspend,
2435 .resume = &genphy_resume,
Allan W. Nielsen4f58e6d2016-10-12 15:47:51 +02002436 .probe = &vsc85xx_probe,
2437 .set_wol = &vsc85xx_wol_set,
2438 .get_wol = &vsc85xx_wol_get,
Raju Lakkaraju310d9ad2016-11-17 13:07:24 +01002439 .get_tunable = &vsc85xx_get_tunable,
2440 .set_tunable = &vsc85xx_set_tunable,
Quentin Schulz6a0bfbb2018-10-08 12:07:23 +02002441 .read_page = &vsc85xx_phy_read_page,
2442 .write_page = &vsc85xx_phy_write_page,
Raju Lakkarajuf76178d2018-10-08 12:07:24 +02002443 .get_sset_count = &vsc85xx_get_sset_count,
2444 .get_strings = &vsc85xx_get_strings,
2445 .get_stats = &vsc85xx_get_stats,
Quentin Schulza5afc162018-10-08 12:14:42 +02002446},
2447{
Quentin Schulz00d70d82018-10-08 12:14:43 +02002448 .phy_id = PHY_ID_VSC8574,
2449 .name = "Microsemi GE VSC8574 SyncE",
2450 .phy_id_mask = 0xfffffff0,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002451 /* PHY_GBIT_FEATURES */
Quentin Schulz00d70d82018-10-08 12:14:43 +02002452 .soft_reset = &genphy_soft_reset,
2453 .config_init = &vsc8584_config_init,
2454 .config_aneg = &vsc85xx_config_aneg,
2455 .aneg_done = &genphy_aneg_done,
2456 .read_status = &vsc85xx_read_status,
2457 .ack_interrupt = &vsc85xx_ack_interrupt,
2458 .config_intr = &vsc85xx_config_intr,
2459 .did_interrupt = &vsc8584_did_interrupt,
2460 .suspend = &genphy_suspend,
2461 .resume = &genphy_resume,
2462 .probe = &vsc8574_probe,
2463 .set_wol = &vsc85xx_wol_set,
2464 .get_wol = &vsc85xx_wol_get,
2465 .get_tunable = &vsc85xx_get_tunable,
2466 .set_tunable = &vsc85xx_set_tunable,
2467 .read_page = &vsc85xx_phy_read_page,
2468 .write_page = &vsc85xx_phy_write_page,
2469 .get_sset_count = &vsc85xx_get_sset_count,
2470 .get_strings = &vsc85xx_get_strings,
2471 .get_stats = &vsc85xx_get_stats,
2472},
2473{
Quentin Schulza5afc162018-10-08 12:14:42 +02002474 .phy_id = PHY_ID_VSC8584,
2475 .name = "Microsemi GE VSC8584 SyncE",
2476 .phy_id_mask = 0xfffffff0,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02002477 /* PHY_GBIT_FEATURES */
Quentin Schulza5afc162018-10-08 12:14:42 +02002478 .soft_reset = &genphy_soft_reset,
2479 .config_init = &vsc8584_config_init,
2480 .config_aneg = &vsc85xx_config_aneg,
2481 .aneg_done = &genphy_aneg_done,
2482 .read_status = &vsc85xx_read_status,
2483 .ack_interrupt = &vsc85xx_ack_interrupt,
2484 .config_intr = &vsc85xx_config_intr,
2485 .did_interrupt = &vsc8584_did_interrupt,
2486 .suspend = &genphy_suspend,
2487 .resume = &genphy_resume,
2488 .probe = &vsc8584_probe,
2489 .get_tunable = &vsc85xx_get_tunable,
2490 .set_tunable = &vsc85xx_set_tunable,
2491 .read_page = &vsc85xx_phy_read_page,
2492 .write_page = &vsc85xx_phy_write_page,
2493 .get_sset_count = &vsc85xx_get_sset_count,
2494 .get_strings = &vsc85xx_get_strings,
2495 .get_stats = &vsc85xx_get_stats,
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302496}
2497
2498};
2499
2500module_phy_driver(vsc85xx_driver);
2501
2502static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
Kavya Sree Kotagirie4f9ba62019-04-22 11:51:35 +00002503 { PHY_ID_VSC8514, 0xfffffff0, },
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002504 { PHY_ID_VSC8530, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302505 { PHY_ID_VSC8531, 0xfffffff0, },
Raju Lakkarajuaf1fee92016-10-28 12:10:11 +02002506 { PHY_ID_VSC8540, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302507 { PHY_ID_VSC8541, 0xfffffff0, },
Quentin Schulz00d70d82018-10-08 12:14:43 +02002508 { PHY_ID_VSC8574, 0xfffffff0, },
Quentin Schulza5afc162018-10-08 12:14:42 +02002509 { PHY_ID_VSC8584, 0xfffffff0, },
Raju Lakkaraju4ffd03f2016-09-08 14:09:31 +05302510 { }
Raju Lakkarajud50736a2016-08-05 17:54:21 +05302511};
2512
2513MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
2514
2515MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
2516MODULE_AUTHOR("Nagaraju Lakkaraju");
2517MODULE_LICENSE("Dual MIT/GPL");