1// SPDX-License-Identifier: MIT
2/*
3 * Microsemi PHY drivers
4 *
5 *
6 * Copyright (c) 2016 Microsemi Corporation
7 *
8 * Author: John Haechten
9 *
10 */
11
12#include <log.h>
13#include <miiphy.h>
14#include <bitfield.h>
15#include <time.h>
16#include <linux/bitops.h>
17#include <linux/delay.h>
18#include <linux/printk.h>
19
20/* Microsemi PHY ID's */
21#define PHY_ID_VSC8530                  0x00070560
22#define PHY_ID_VSC8531                  0x00070570
23#define PHY_ID_VSC8502			0x00070630
24#define PHY_ID_VSC8540                  0x00070760
25#define PHY_ID_VSC8541                  0x00070770
26#define PHY_ID_VSC8574			0x000704a0
27#define PHY_ID_VSC8584                  0x000707c0
28
29/* Microsemi VSC85xx PHY Register Pages */
30#define MSCC_EXT_PAGE_ACCESS            31     /* Page Access Register */
31#define MSCC_PHY_PAGE_STD		0x0000 /* Standard registers */
32#define MSCC_PHY_PAGE_EXT1		0x0001 /* Extended registers - page 1 */
33#define MSCC_PHY_PAGE_EXT2		0x0002 /* Extended registers - page 2 */
34#define MSCC_PHY_PAGE_EXT3		0x0003 /* Extended registers - page 3 */
35#define MSCC_PHY_PAGE_EXT4		0x0004 /* Extended registers - page 4 */
36#define MSCC_PHY_PAGE_GPIO		0x0010 /* GPIO registers */
37#define MSCC_PHY_PAGE_TEST		0x2A30 /* TEST Page registers */
38#define MSCC_PHY_PAGE_TR		0x52B5 /* Token Ring Page registers */
39
40/* Std Page Register 18 */
41#define MSCC_PHY_BYPASS_CONTROL           18
42#define PARALLEL_DET_IGNORE_ADVERTISED    BIT(3)
43
44/* Std Page Register 22 */
45#define MSCC_PHY_EXT_CNTL_STATUS          22
46#define SMI_BROADCAST_WR_EN              BIT(0)
47
48/* Std Page Register 24 */
49#define MSCC_PHY_EXT_PHY_CNTL_2           24
50
51/* Std Page Register 28 - PHY AUX Control/Status */
52#define MIIM_AUX_CNTRL_STAT_REG		28
53#define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO	(0x0004)
54#define MIIM_AUX_CNTRL_STAT_F_DUPLEX	(0x0020)
55#define MIIM_AUX_CNTRL_STAT_SPEED_MASK	(0x0018)
56#define MIIM_AUX_CNTRL_STAT_SPEED_POS	(3)
57#define MIIM_AUX_CNTRL_STAT_SPEED_10M	(0x0)
58#define MIIM_AUX_CNTRL_STAT_SPEED_100M	(0x1)
59#define MIIM_AUX_CNTRL_STAT_SPEED_1000M	(0x2)
60
61/* Std Page Register 23 - Extended PHY CTRL_1 */
62#define MSCC_PHY_EXT_PHY_CNTL_1_REG	23
63#define MAC_IF_SELECTION_MASK		(0x1800)
64#define MAC_IF_SELECTION_GMII		(0)
65#define MAC_IF_SELECTION_RMII		(1)
66#define MAC_IF_SELECTION_RGMII		(2)
67#define MAC_IF_SELECTION_POS		(11)
68#define MAC_IF_SELECTION_WIDTH		(2)
69#define VSC8584_MAC_IF_SELECTION_MASK     BIT(12)
70#define VSC8584_MAC_IF_SELECTION_SGMII    0
71#define VSC8584_MAC_IF_SELECTION_1000BASEX 1
72#define VSC8584_MAC_IF_SELECTION_POS      12
73#define MEDIA_OP_MODE_MASK		  GENMASK(10, 8)
74#define MEDIA_OP_MODE_COPPER		  0
75#define MEDIA_OP_MODE_SERDES		  1
76#define MEDIA_OP_MODE_1000BASEX		  2
77#define MEDIA_OP_MODE_100BASEFX		  3
78#define MEDIA_OP_MODE_AMS_COPPER_SERDES	  5
79#define MEDIA_OP_MODE_AMS_COPPER_1000BASEX	6
80#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX	7
81#define MEDIA_OP_MODE_POS		  8
82
83/* Extended Page 1 Register 20E1 */
84#define MSCC_PHY_ACTIPHY_CNTL		  20
85#define PHY_ADDR_REVERSED		  BIT(9)
86
87/* Extended Page 1 Register 23E1 */
88
89#define MSCC_PHY_EXT_PHY_CNTL_4           23
90#define PHY_CNTL_4_ADDR_POS		  11
91
92/* Extended Page 1 Register 25E1 */
93#define MSCC_PHY_VERIPHY_CNTL_2		25
94
95/* Extended Page 1 Register 26E1 */
96#define MSCC_PHY_VERIPHY_CNTL_3		26
97
98/* Extended Page 2 Register 16E2 */
99#define MSCC_PHY_CU_PMD_TX_CNTL         16
100
101/* Extended Page 2 Register 20E2 */
102#define MSCC_PHY_RGMII_CNTL_REG		20
103#define VSC_FAST_LINK_FAIL2_ENA_MASK	(0x8000)
104#define RX_CLK_OUT_MASK			(0x0800)
105#define RX_CLK_OUT_POS			(11)
106#define RX_CLK_OUT_WIDTH		(1)
107#define RX_CLK_OUT_NORMAL		(0)
108#define RX_CLK_OUT_DISABLE		(1)
109#define RGMII_RX_CLK_DELAY_POS		(4)
110#define RGMII_RX_CLK_DELAY_WIDTH	(3)
111#define RGMII_RX_CLK_DELAY_MASK		(0x0070)
112#define RGMII_TX_CLK_DELAY_POS		(0)
113#define RGMII_TX_CLK_DELAY_WIDTH	(3)
114#define RGMII_TX_CLK_DELAY_MASK		(0x0007)
115
116/* Extended Page 2 Register 27E2 */
117#define MSCC_PHY_WOL_MAC_CONTROL	27
118#define EDGE_RATE_CNTL_POS		(5)
119#define EDGE_RATE_CNTL_WIDTH		(3)
120#define EDGE_RATE_CNTL_MASK		(0x00E0)
121#define RMII_CLK_OUT_ENABLE_POS		(4)
122#define RMII_CLK_OUT_ENABLE_WIDTH	(1)
123#define RMII_CLK_OUT_ENABLE_MASK	(0x10)
124
125/* Extended Page 3 Register 22E3 */
126#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT	22
127
128/* Extended page GPIO register 00G */
129#define MSCC_DW8051_CNTL_STATUS		0
130#define MICRO_NSOFT_RESET		BIT(15)
131#define RUN_FROM_INT_ROM		BIT(14)
132#define AUTOINC_ADDR			BIT(13)
133#define PATCH_RAM_CLK			BIT(12)
134#define MICRO_PATCH_EN			BIT(7)
135#define DW8051_CLK_EN			BIT(4)
136#define MICRO_CLK_EN			BIT(3)
137#define MICRO_CLK_DIVIDE(x)		((x) >> 1)
138#define MSCC_DW8051_VLD_MASK		0xf1ff
139
140/* Extended page GPIO register 09G */
141#define MSCC_TRAP_ROM_ADDR(x)		((x) * 2 + 1)
142#define MSCC_TRAP_ROM_ADDR_SERDES_INIT	0x3eb7
143
144/* Extended page GPIO register 10G */
145#define MSCC_PATCH_RAM_ADDR(x)		(((x) + 1) * 2)
146#define MSCC_PATCH_RAM_ADDR_SERDES_INIT	0x4012
147
148/* Extended page GPIO register 11G */
149#define MSCC_INT_MEM_ADDR		11
150
151/* Extended page GPIO register 12G */
152#define MSCC_INT_MEM_CNTL		12
153#define READ_SFR			(BIT(14) | BIT(13))
154#define READ_PRAM			BIT(14)
155#define READ_ROM			BIT(13)
156#define READ_RAM			(0x00 << 13)
157#define INT_MEM_WRITE_EN		BIT(12)
158#define EN_PATCH_RAM_TRAP_ADDR(x)	BIT((x) + 7)
159#define INT_MEM_DATA_M			GENMASK(7, 0)
160#define INT_MEM_DATA(x)			(INT_MEM_DATA_M & (x))
161
162/* Extended page GPIO register 13G */
163#define MSCC_CLKOUT_CNTL		13
164#define CLKOUT_ENABLE			BIT(15)
165#define CLKOUT_FREQ_MASK		GENMASK(14, 13)
166#define CLKOUT_FREQ_25M			(0x0 << 13)
167#define CLKOUT_FREQ_50M			(0x1 << 13)
168#define CLKOUT_FREQ_125M		(0x2 << 13)
169
170/* Extended page GPIO register 18G */
171#define MSCC_PHY_PROC_CMD		  18
172#define PROC_CMD_NCOMPLETED		  BIT(15)
173#define PROC_CMD_FAILED			  BIT(14)
174#define PROC_CMD_SGMII_PORT(x)		  ((x) << 8)
175#define PROC_CMD_FIBER_PORT(x)		  BIT(8 + (x) % 4)
176#define PROC_CMD_QSGMII_PORT		  (BIT(11) | BIT(10))
177#define PROC_CMD_RST_CONF_PORT		  BIT(7)
178#define PROC_CMD_RECONF_PORT		  (0 << 7)
179#define PROC_CMD_READ_MOD_WRITE_PORT	  BIT(6)
180#define PROC_CMD_WRITE			  BIT(6)
181#define PROC_CMD_READ			  (0 << 6)
182#define PROC_CMD_FIBER_DISABLE		  BIT(5)
183#define PROC_CMD_FIBER_100BASE_FX	  BIT(4)
184#define PROC_CMD_FIBER_1000BASE_X	  (0 << 4)
185#define PROC_CMD_SGMII_MAC		  (BIT(5) | BIT(4))
186#define PROC_CMD_QSGMII_MAC		  BIT(5)
187#define PROC_CMD_NO_MAC_CONF		  (0x00 << 4)
188#define PROC_CMD_1588_DEFAULT_INIT	  BIT(4)
189#define PROC_CMD_NOP			  GENMASK(3, 0)
190#define PROC_CMD_PHY_INIT		  (BIT(3) | BIT(1))
191#define PROC_CMD_CRC16			  BIT(3)
192#define PROC_CMD_FIBER_MEDIA_CONF	  BIT(0)
193#define PROC_CMD_MCB_ACCESS_MAC_CONF	  (0x0000 << 0)
194#define PROC_CMD_NCOMPLETED_TIMEOUT_MS    500
195
196/* Extended page GPIO register 19G */
197#define MSCC_PHY_MAC_CFG_FASTLINK	  19
198#define MAC_CFG_MASK			  GENMASK(15, 14)
199#define MAC_CFG_SGMII			  (0x00 << 14)
200#define MAC_CFG_QSGMII			  BIT(14)
201
202/* Test Registers */
203#define MSCC_PHY_TEST_PAGE_5		5
204
205#define MSCC_PHY_TEST_PAGE_8		8
206#define TR_CLK_DISABLE			BIT(15)
207
208#define MSCC_PHY_TEST_PAGE_9		9
209#define MSCC_PHY_TEST_PAGE_20		20
210#define MSCC_PHY_TEST_PAGE_24		24
211
212/* Token Ring Page 0x52B5 Registers */
213#define MSCC_PHY_REG_TR_ADDR_16		16
214#define MSCC_PHY_REG_TR_DATA_17		17
215#define MSCC_PHY_REG_TR_DATA_18		18
216
217/* Token Ring - Read Value in */
218#define MSCC_PHY_TR_16_READ		(0xA000)
219/* Token Ring - Write Value out */
220#define MSCC_PHY_TR_16_WRITE		(0x8000)
221
222/* Token Ring Registers */
223#define MSCC_PHY_TR_LINKDETCTRL_POS	(3)
224#define MSCC_PHY_TR_LINKDETCTRL_WIDTH	(2)
225#define MSCC_PHY_TR_LINKDETCTRL_VAL	(3)
226#define MSCC_PHY_TR_LINKDETCTRL_MASK	(0x0018)
227#define MSCC_PHY_TR_LINKDETCTRL_ADDR	(0x07F8)
228
229#define MSCC_PHY_TR_VGATHRESH100_POS	(0)
230#define MSCC_PHY_TR_VGATHRESH100_WIDTH	(7)
231#define MSCC_PHY_TR_VGATHRESH100_VAL	(0x0018)
232#define MSCC_PHY_TR_VGATHRESH100_MASK	(0x007f)
233#define MSCC_PHY_TR_VGATHRESH100_ADDR	(0x0FA4)
234
235#define MSCC_PHY_TR_VGAGAIN10_U_POS	(0)
236#define MSCC_PHY_TR_VGAGAIN10_U_WIDTH	(1)
237#define MSCC_PHY_TR_VGAGAIN10_U_MASK	(0x0001)
238#define MSCC_PHY_TR_VGAGAIN10_U_VAL	(0)
239
240#define MSCC_PHY_TR_VGAGAIN10_L_POS	(12)
241#define MSCC_PHY_TR_VGAGAIN10_L_WIDTH	(4)
242#define MSCC_PHY_TR_VGAGAIN10_L_MASK	(0xf000)
243#define MSCC_PHY_TR_VGAGAIN10_L_VAL	(0x0001)
244#define MSCC_PHY_TR_VGAGAIN10_ADDR	(0x0F92)
245
246/* General Timeout Values */
247#define MSCC_PHY_RESET_TIMEOUT		(100)
248#define MSCC_PHY_MICRO_TIMEOUT		(500)
249
250#define VSC8584_REVB		0x0001
251#define MSCC_DEV_REV_MASK	GENMASK(3, 0)
252
253#define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR 0x4000
254#define MSCC_VSC8574_REVB_INT8051_FW_CRC	0x29e8
255
256#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR	0xe800
257#define MSCC_VSC8584_REVB_INT8051_FW_CRC	0xfb48
258
259/* RGMII/GMII Clock Delay (Skew) Options */ enum vsc_phy_rgmii_skew {
260	VSC_PHY_RGMII_DELAY_200_PS,
261	VSC_PHY_RGMII_DELAY_800_PS,
262	VSC_PHY_RGMII_DELAY_1100_PS,
263	VSC_PHY_RGMII_DELAY_1700_PS,
264	VSC_PHY_RGMII_DELAY_2000_PS,
265	VSC_PHY_RGMII_DELAY_2300_PS,
266	VSC_PHY_RGMII_DELAY_2600_PS,
267	VSC_PHY_RGMII_DELAY_3400_PS,
268};
269
270/* MAC i/f Clock Edge Rage Control (Slew), See Reg27E2  */ enum
271vsc_phy_clk_slew {
272	VSC_PHY_CLK_SLEW_RATE_0,
273	VSC_PHY_CLK_SLEW_RATE_1,
274	VSC_PHY_CLK_SLEW_RATE_2,
275	VSC_PHY_CLK_SLEW_RATE_3,
276	VSC_PHY_CLK_SLEW_RATE_4,
277	VSC_PHY_CLK_SLEW_RATE_5,
278	VSC_PHY_CLK_SLEW_RATE_6,
279	VSC_PHY_CLK_SLEW_RATE_7,
280};
281
282struct vsc85xx_priv {
283	int (*config_pre)(struct phy_device *phydev);
284};
285
286static void vsc8584_csr_write(struct mii_dev *bus, int phy0, u16 addr, u32 val)
287{
288	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18,
289		   val >> 16);
290	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17,
291		   val & GENMASK(15, 0));
292	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
293		   MSCC_PHY_TR_16_WRITE | addr);
294}
295
296static int vsc8584_cmd(struct mii_dev *bus, int phy, u16 val)
297{
298	unsigned long deadline;
299	u16 reg_val;
300
301	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
302		   MSCC_PHY_PAGE_GPIO);
303
304	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_PROC_CMD,
305		   PROC_CMD_NCOMPLETED | val);
306
307	deadline = timer_get_us() + PROC_CMD_NCOMPLETED_TIMEOUT_MS * 1000;
308	do {
309		reg_val = bus->read(bus, phy, MDIO_DEVAD_NONE,
310				    MSCC_PHY_PROC_CMD);
311	} while (timer_get_us() <= deadline &&
312		 (reg_val & PROC_CMD_NCOMPLETED) &&
313		 !(reg_val & PROC_CMD_FAILED));
314
315	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
316		   MSCC_PHY_PAGE_STD);
317
318	if (reg_val & PROC_CMD_FAILED)
319		return -EIO;
320	if (reg_val & PROC_CMD_NCOMPLETED)
321		return -ETIMEDOUT;
322
323	return 0;
324}
325
326static int vsc8584_micro_deassert_reset(struct mii_dev *bus, int phy,
327					bool patch_en)
328{
329	u32 enable, release;
330
331	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
332		   MSCC_PHY_PAGE_GPIO);
333
334	enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
335	release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
336		MICRO_CLK_EN;
337
338	if (patch_en) {
339		enable |= MICRO_PATCH_EN;
340		release |= MICRO_PATCH_EN;
341
342		/* Clear all patches */
343		bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL,
344			   READ_RAM);
345	}
346
347	/*
348	 * Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock
349	 * override and addr. auto-incr; operate at 125 MHz
350	 */
351	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS, enable);
352	/* Release 8051 Micro SW reset */
353	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS, release);
354
355	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
356		   MSCC_PHY_PAGE_STD);
357
358	return 0;
359}
360
361static int vsc8584_micro_assert_reset(struct mii_dev *bus, int phy)
362{
363	int ret;
364	u16 reg;
365
366	ret = vsc8584_cmd(bus, phy, PROC_CMD_NOP);
367	if (ret)
368		return ret;
369
370	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
371		   MSCC_PHY_PAGE_GPIO);
372
373	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
374	reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
375	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, reg);
376
377	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_TRAP_ROM_ADDR(4), 0x005b);
378	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PATCH_RAM_ADDR(4), 0x005b);
379
380	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
381	reg |= EN_PATCH_RAM_TRAP_ADDR(4);
382	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, reg);
383
384	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
385
386	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS);
387	reg &= ~MICRO_NSOFT_RESET;
388	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS, reg);
389
390	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_PROC_CMD,
391		   PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_SGMII_PORT(0) |
392		   PROC_CMD_NO_MAC_CONF | PROC_CMD_READ);
393
394	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
395	reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
396	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, reg);
397
398	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
399		   MSCC_PHY_PAGE_STD);
400
401	return 0;
402}
403
404static const u8 fw_patch_vsc8574[] = {
405	0x46, 0x4a, 0x02, 0x43, 0x37, 0x02, 0x46, 0x26, 0x02, 0x46, 0x77, 0x02,
406	0x45, 0x60, 0x02, 0x45, 0xaf, 0xed, 0xff, 0xe5, 0xfc, 0x54, 0x38, 0x64,
407	0x20, 0x70, 0x08, 0x65, 0xff, 0x70, 0x04, 0xed, 0x44, 0x80, 0xff, 0x22,
408	0x8f, 0x19, 0x7b, 0xbb, 0x7d, 0x0e, 0x7f, 0x04, 0x12, 0x3d, 0xd7, 0xef,
409	0x4e, 0x60, 0x03, 0x02, 0x41, 0xf9, 0xe4, 0xf5, 0x1a, 0x74, 0x01, 0x7e,
410	0x00, 0xa8, 0x1a, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8,
411	0xf9, 0xff, 0xef, 0x55, 0x19, 0x70, 0x03, 0x02, 0x41, 0xed, 0x85, 0x1a,
412	0xfb, 0x7b, 0xbb, 0xe4, 0xfd, 0xff, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60,
413	0x03, 0x02, 0x41, 0xed, 0xe5, 0x1a, 0x54, 0x02, 0x75, 0x1d, 0x00, 0x25,
414	0xe0, 0x25, 0xe0, 0xf5, 0x1c, 0xe4, 0x78, 0xc5, 0xf6, 0xd2, 0x0a, 0x12,
415	0x41, 0xfa, 0x7b, 0xff, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef,
416	0x4e, 0x60, 0x03, 0x02, 0x41, 0xe7, 0xc2, 0x0a, 0x74, 0xc7, 0x25, 0x1a,
417	0xf9, 0x74, 0xe7, 0x25, 0x1a, 0xf8, 0xe6, 0x27, 0xf5, 0x1b, 0xe5, 0x1d,
418	0x24, 0x5b, 0x12, 0x45, 0xea, 0x12, 0x3e, 0xda, 0x7b, 0xfc, 0x7d, 0x11,
419	0x7f, 0x07, 0x12, 0x3d, 0xd7, 0x78, 0xcc, 0xef, 0xf6, 0x78, 0xc1, 0xe6,
420	0xfe, 0xef, 0xd3, 0x9e, 0x40, 0x06, 0x78, 0xcc, 0xe6, 0x78, 0xc1, 0xf6,
421	0x12, 0x41, 0xfa, 0x7b, 0xec, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7,
422	0x78, 0xcb, 0xef, 0xf6, 0xbf, 0x07, 0x06, 0x78, 0xc3, 0x76, 0x1a, 0x80,
423	0x1f, 0x78, 0xc5, 0xe6, 0xff, 0x60, 0x0f, 0xc3, 0xe5, 0x1b, 0x9f, 0xff,
424	0x78, 0xcb, 0xe6, 0x85, 0x1b, 0xf0, 0xa4, 0x2f, 0x80, 0x07, 0x78, 0xcb,
425	0xe6, 0x85, 0x1b, 0xf0, 0xa4, 0x78, 0xc3, 0xf6, 0xe4, 0x78, 0xc2, 0xf6,
426	0x78, 0xc2, 0xe6, 0xff, 0xc3, 0x08, 0x96, 0x40, 0x03, 0x02, 0x41, 0xd1,
427	0xef, 0x54, 0x03, 0x60, 0x33, 0x14, 0x60, 0x46, 0x24, 0xfe, 0x60, 0x42,
428	0x04, 0x70, 0x4b, 0xef, 0x24, 0x02, 0xff, 0xe4, 0x33, 0xfe, 0xef, 0x78,
429	0x02, 0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0xd8, 0xf8, 0xff, 0xe5, 0x1d,
430	0x24, 0x5c, 0xcd, 0xe5, 0x1c, 0x34, 0xf0, 0xcd, 0x2f, 0xff, 0xed, 0x3e,
431	0xfe, 0x12, 0x46, 0x0d, 0x7d, 0x11, 0x80, 0x0b, 0x78, 0xc2, 0xe6, 0x70,
432	0x04, 0x7d, 0x11, 0x80, 0x02, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3e, 0x9a,
433	0x8e, 0x1e, 0x8f, 0x1f, 0x80, 0x03, 0xe5, 0x1e, 0xff, 0x78, 0xc5, 0xe6,
434	0x06, 0x24, 0xcd, 0xf8, 0xa6, 0x07, 0x78, 0xc2, 0x06, 0xe6, 0xb4, 0x1a,
435	0x0a, 0xe5, 0x1d, 0x24, 0x5c, 0x12, 0x45, 0xea, 0x12, 0x3e, 0xda, 0x78,
436	0xc5, 0xe6, 0x65, 0x1b, 0x70, 0x82, 0x75, 0xdb, 0x20, 0x75, 0xdb, 0x28,
437	0x12, 0x46, 0x02, 0x12, 0x46, 0x02, 0xe5, 0x1a, 0x12, 0x45, 0xf5, 0xe5,
438	0x1a, 0xc3, 0x13, 0x12, 0x45, 0xf5, 0x78, 0xc5, 0x16, 0xe6, 0x24, 0xcd,
439	0xf8, 0xe6, 0xff, 0x7e, 0x08, 0x1e, 0xef, 0xa8, 0x06, 0x08, 0x80, 0x02,
440	0xc3, 0x13, 0xd8, 0xfc, 0xfd, 0xc4, 0x33, 0x54, 0xe0, 0xf5, 0xdb, 0xef,
441	0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x13, 0xd8, 0xfc, 0xfd, 0xc4, 0x33,
442	0x54, 0xe0, 0x44, 0x08, 0xf5, 0xdb, 0xee, 0x70, 0xd8, 0x78, 0xc5, 0xe6,
443	0x70, 0xc8, 0x75, 0xdb, 0x10, 0x02, 0x40, 0xfd, 0x78, 0xc2, 0xe6, 0xc3,
444	0x94, 0x17, 0x50, 0x0e, 0xe5, 0x1d, 0x24, 0x62, 0x12, 0x42, 0x08, 0xe5,
445	0x1d, 0x24, 0x5c, 0x12, 0x42, 0x08, 0x20, 0x0a, 0x03, 0x02, 0x40, 0x76,
446	0x05, 0x1a, 0xe5, 0x1a, 0xc3, 0x94, 0x04, 0x50, 0x03, 0x02, 0x40, 0x3a,
447	0x22, 0xe5, 0x1d, 0x24, 0x5c, 0xff, 0xe5, 0x1c, 0x34, 0xf0, 0xfe, 0x12,
448	0x46, 0x0d, 0x22, 0xff, 0xe5, 0x1c, 0x34, 0xf0, 0xfe, 0x12, 0x46, 0x0d,
449	0x22, 0xe4, 0xf5, 0x19, 0x12, 0x46, 0x43, 0x20, 0xe7, 0x1e, 0x7b, 0xfe,
450	0x12, 0x42, 0xf9, 0xef, 0xc4, 0x33, 0x33, 0x54, 0xc0, 0xff, 0xc0, 0x07,
451	0x7b, 0x54, 0x12, 0x42, 0xf9, 0xd0, 0xe0, 0x4f, 0xff, 0x74, 0x2a, 0x25,
452	0x19, 0xf8, 0xa6, 0x07, 0x12, 0x46, 0x43, 0x20, 0xe7, 0x03, 0x02, 0x42,
453	0xdf, 0x54, 0x03, 0x64, 0x03, 0x70, 0x03, 0x02, 0x42, 0xcf, 0x7b, 0xcb,
454	0x12, 0x43, 0x2c, 0x8f, 0xfb, 0x7b, 0x30, 0x7d, 0x03, 0xe4, 0xff, 0x12,
455	0x3d, 0xd7, 0xc3, 0xef, 0x94, 0x02, 0xee, 0x94, 0x00, 0x50, 0x2a, 0x12,
456	0x42, 0xec, 0xef, 0x4e, 0x70, 0x23, 0x12, 0x43, 0x04, 0x60, 0x0a, 0x12,
457	0x43, 0x12, 0x70, 0x0c, 0x12, 0x43, 0x1f, 0x70, 0x07, 0x12, 0x46, 0x39,
458	0x7b, 0x03, 0x80, 0x07, 0x12, 0x46, 0x39, 0x12, 0x46, 0x43, 0xfb, 0x7a,
459	0x00, 0x7d, 0x54, 0x80, 0x3e, 0x12, 0x42, 0xec, 0xef, 0x4e, 0x70, 0x24,
460	0x12, 0x43, 0x04, 0x60, 0x0a, 0x12, 0x43, 0x12, 0x70, 0x0f, 0x12, 0x43,
461	0x1f, 0x70, 0x0a, 0x12, 0x46, 0x39, 0xe4, 0xfb, 0xfa, 0x7d, 0xee, 0x80,
462	0x1e, 0x12, 0x46, 0x39, 0x7b, 0x01, 0x7a, 0x00, 0x7d, 0xee, 0x80, 0x13,
463	0x12, 0x46, 0x39, 0x12, 0x46, 0x43, 0x54, 0x40, 0xfe, 0xc4, 0x13, 0x13,
464	0x54, 0x03, 0xfb, 0x7a, 0x00, 0x7d, 0xee, 0x12, 0x38, 0xbd, 0x7b, 0xff,
465	0x12, 0x43, 0x2c, 0xef, 0x4e, 0x70, 0x07, 0x74, 0x2a, 0x25, 0x19, 0xf8,
466	0xe4, 0xf6, 0x05, 0x19, 0xe5, 0x19, 0xc3, 0x94, 0x02, 0x50, 0x03, 0x02,
467	0x42, 0x15, 0x22, 0xe5, 0x19, 0x24, 0x17, 0xfd, 0x7b, 0x20, 0x7f, 0x04,
468	0x12, 0x3d, 0xd7, 0x22, 0xe5, 0x19, 0x24, 0x17, 0xfd, 0x7f, 0x04, 0x12,
469	0x3d, 0xd7, 0x22, 0x7b, 0x22, 0x7d, 0x18, 0x7f, 0x06, 0x12, 0x3d, 0xd7,
470	0xef, 0x64, 0x01, 0x4e, 0x22, 0x7d, 0x1c, 0xe4, 0xff, 0x12, 0x3e, 0x9a,
471	0xef, 0x54, 0x1b, 0x64, 0x0a, 0x22, 0x7b, 0xcc, 0x7d, 0x10, 0xff, 0x12,
472	0x3d, 0xd7, 0xef, 0x64, 0x01, 0x4e, 0x22, 0xe5, 0x19, 0x24, 0x17, 0xfd,
473	0x7f, 0x04, 0x12, 0x3d, 0xd7, 0x22, 0xd2, 0x08, 0x75, 0xfb, 0x03, 0xab,
474	0x7e, 0xaa, 0x7d, 0x7d, 0x19, 0x7f, 0x03, 0x12, 0x3e, 0xda, 0xe5, 0x7e,
475	0x54, 0x0f, 0x24, 0xf3, 0x60, 0x03, 0x02, 0x43, 0xe9, 0x12, 0x46, 0x5a,
476	0x12, 0x46, 0x61, 0xd8, 0xfb, 0xff, 0x20, 0xe2, 0x35, 0x13, 0x92, 0x0c,
477	0xef, 0xa2, 0xe1, 0x92, 0x0b, 0x30, 0x0c, 0x2a, 0xe4, 0xf5, 0x10, 0x7b,
478	0xfe, 0x12, 0x43, 0xff, 0xef, 0xc4, 0x33, 0x33, 0x54, 0xc0, 0xff, 0xc0,
479	0x07, 0x7b, 0x54, 0x12, 0x43, 0xff, 0xd0, 0xe0, 0x4f, 0xff, 0x74, 0x2a,
480	0x25, 0x10, 0xf8, 0xa6, 0x07, 0x05, 0x10, 0xe5, 0x10, 0xc3, 0x94, 0x02,
481	0x40, 0xd9, 0x12, 0x46, 0x5a, 0x12, 0x46, 0x61, 0xd8, 0xfb, 0x54, 0x05,
482	0x64, 0x04, 0x70, 0x27, 0x78, 0xc4, 0xe6, 0x78, 0xc6, 0xf6, 0xe5, 0x7d,
483	0xff, 0x33, 0x95, 0xe0, 0xef, 0x54, 0x0f, 0x78, 0xc4, 0xf6, 0x12, 0x44,
484	0x0a, 0x20, 0x0c, 0x0c, 0x12, 0x46, 0x5a, 0x12, 0x46, 0x61, 0xd8, 0xfb,
485	0x13, 0x92, 0x0d, 0x22, 0xc2, 0x0d, 0x22, 0x12, 0x46, 0x5a, 0x12, 0x46,
486	0x61, 0xd8, 0xfb, 0x54, 0x05, 0x64, 0x05, 0x70, 0x1e, 0x78, 0xc4, 0x7d,
487	0xb8, 0x12, 0x43, 0xf5, 0x78, 0xc1, 0x7d, 0x74, 0x12, 0x43, 0xf5, 0xe4,
488	0x78, 0xc1, 0xf6, 0x22, 0x7b, 0x01, 0x7a, 0x00, 0x7d, 0xee, 0x7f, 0x92,
489	0x12, 0x38, 0xbd, 0x22, 0xe6, 0xfb, 0x7a, 0x00, 0x7f, 0x92, 0x12, 0x38,
490	0xbd, 0x22, 0xe5, 0x10, 0x24, 0x17, 0xfd, 0x7f, 0x04, 0x12, 0x3d, 0xd7,
491	0x22, 0x78, 0xc1, 0xe6, 0xfb, 0x7a, 0x00, 0x7d, 0x74, 0x7f, 0x92, 0x12,
492	0x38, 0xbd, 0xe4, 0x78, 0xc1, 0xf6, 0xf5, 0x11, 0x74, 0x01, 0x7e, 0x00,
493	0xa8, 0x11, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9,
494	0xff, 0x78, 0xc4, 0xe6, 0xfd, 0xef, 0x5d, 0x60, 0x44, 0x85, 0x11, 0xfb,
495	0xe5, 0x11, 0x54, 0x02, 0x25, 0xe0, 0x25, 0xe0, 0xfe, 0xe4, 0x24, 0x5b,
496	0xfb, 0xee, 0x12, 0x45, 0xed, 0x12, 0x3e, 0xda, 0x7b, 0x40, 0x7d, 0x11,
497	0x7f, 0x07, 0x12, 0x3d, 0xd7, 0x74, 0xc7, 0x25, 0x11, 0xf8, 0xa6, 0x07,
498	0x7b, 0x11, 0x7d, 0x12, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60,
499	0x09, 0x74, 0xe7, 0x25, 0x11, 0xf8, 0x76, 0x04, 0x80, 0x07, 0x74, 0xe7,
500	0x25, 0x11, 0xf8, 0x76, 0x0a, 0x05, 0x11, 0xe5, 0x11, 0xc3, 0x94, 0x04,
501	0x40, 0x9a, 0x78, 0xc6, 0xe6, 0x70, 0x15, 0x78, 0xc4, 0xe6, 0x60, 0x10,
502	0x75, 0xd9, 0x38, 0x75, 0xdb, 0x10, 0x7d, 0xfe, 0x12, 0x44, 0xb8, 0x7d,
503	0x76, 0x12, 0x44, 0xb8, 0x79, 0xc6, 0xe7, 0x78, 0xc4, 0x66, 0xff, 0x60,
504	0x03, 0x12, 0x40, 0x25, 0x78, 0xc4, 0xe6, 0x70, 0x09, 0xfb, 0xfa, 0x7d,
505	0xfe, 0x7f, 0x8e, 0x12, 0x38, 0xbd, 0x22, 0x7b, 0x01, 0x7a, 0x00, 0x7f,
506	0x8e, 0x12, 0x38, 0xbd, 0x22, 0xe4, 0xf5, 0xfb, 0x7d, 0x1c, 0xe4, 0xff,
507	0x12, 0x3e, 0x9a, 0xad, 0x07, 0xac, 0x06, 0xec, 0x54, 0xc0, 0xff, 0xed,
508	0x54, 0x3f, 0x4f, 0xf5, 0x20, 0x30, 0x06, 0x2c, 0x30, 0x01, 0x08, 0xa2,
509	0x04, 0x72, 0x03, 0x92, 0x07, 0x80, 0x21, 0x30, 0x04, 0x06, 0x7b, 0xcc,
510	0x7d, 0x11, 0x80, 0x0d, 0x30, 0x03, 0x06, 0x7b, 0xcc, 0x7d, 0x10, 0x80,
511	0x04, 0x7b, 0x66, 0x7d, 0x16, 0xe4, 0xff, 0x12, 0x3d, 0xd7, 0xee, 0x4f,
512	0x24, 0xff, 0x92, 0x07, 0xaf, 0xfb, 0x74, 0x26, 0x2f, 0xf8, 0xe6, 0xff,
513	0xa6, 0x20, 0x20, 0x07, 0x39, 0x8f, 0x20, 0x30, 0x07, 0x34, 0x30, 0x00,
514	0x31, 0x20, 0x04, 0x2e, 0x20, 0x03, 0x2b, 0xe4, 0xf5, 0xff, 0x75, 0xfc,
515	0xc2, 0xe5, 0xfc, 0x30, 0xe0, 0xfb, 0xaf, 0xfe, 0xef, 0x20, 0xe3, 0x1a,
516	0xae, 0xfd, 0x44, 0x08, 0xf5, 0xfe, 0x75, 0xfc, 0x80, 0xe5, 0xfc, 0x30,
517	0xe0, 0xfb, 0x8f, 0xfe, 0x8e, 0xfd, 0x75, 0xfc, 0x80, 0xe5, 0xfc, 0x30,
518	0xe0, 0xfb, 0x05, 0xfb, 0xaf, 0xfb, 0xef, 0xc3, 0x94, 0x04, 0x50, 0x03,
519	0x02, 0x44, 0xc5, 0xe4, 0xf5, 0xfb, 0x22, 0xe5, 0x7e, 0x54, 0x0f, 0x64,
520	0x01, 0x70, 0x23, 0xe5, 0x7e, 0x30, 0xe4, 0x1e, 0x90, 0x47, 0xd0, 0xe0,
521	0x44, 0x02, 0xf0, 0x54, 0xfb, 0xf0, 0x90, 0x47, 0xd4, 0xe0, 0x44, 0x04,
522	0xf0, 0x7b, 0x03, 0x7d, 0x5b, 0x7f, 0x5d, 0x12, 0x36, 0x29, 0x7b, 0x0e,
523	0x80, 0x1c, 0x90, 0x47, 0xd0, 0xe0, 0x54, 0xfd, 0xf0, 0x44, 0x04, 0xf0,
524	0x90, 0x47, 0xd4, 0xe0, 0x54, 0xfb, 0xf0, 0x7b, 0x02, 0x7d, 0x5b, 0x7f,
525	0x5d, 0x12, 0x36, 0x29, 0x7b, 0x06, 0x7d, 0x60, 0x7f, 0x63, 0x12, 0x36,
526	0x29, 0x22, 0xe5, 0x7e, 0x30, 0xe5, 0x35, 0x30, 0xe4, 0x0b, 0x7b, 0x02,
527	0x7d, 0x33, 0x7f, 0x35, 0x12, 0x36, 0x29, 0x80, 0x10, 0x7b, 0x01, 0x7d,
528	0x33, 0x7f, 0x35, 0x12, 0x36, 0x29, 0x90, 0x47, 0xd2, 0xe0, 0x44, 0x04,
529	0xf0, 0x90, 0x47, 0xd2, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x47, 0xd1, 0xe0,
530	0x44, 0x10, 0xf0, 0x7b, 0x05, 0x7d, 0x84, 0x7f, 0x86, 0x12, 0x36, 0x29,
531	0x22, 0xfb, 0xe5, 0x1c, 0x34, 0xf0, 0xfa, 0x7d, 0x10, 0x7f, 0x07, 0x22,
532	0x54, 0x01, 0xc4, 0x33, 0x54, 0xe0, 0xf5, 0xdb, 0x44, 0x08, 0xf5, 0xdb,
533	0x22, 0xf5, 0xdb, 0x75, 0xdb, 0x08, 0xf5, 0xdb, 0x75, 0xdb, 0x08, 0x22,
534	0xab, 0x07, 0xaa, 0x06, 0x7d, 0x10, 0x7f, 0x07, 0x12, 0x3e, 0xda, 0x7b,
535	0xff, 0x7d, 0x10, 0x7f, 0x07, 0x12, 0x3d, 0xd7, 0xef, 0x4e, 0x60, 0xf3,
536	0x22, 0x12, 0x44, 0xc2, 0x30, 0x0c, 0x03, 0x12, 0x42, 0x12, 0x78, 0xc4,
537	0xe6, 0xff, 0x60, 0x03, 0x12, 0x40, 0x25, 0x22, 0xe5, 0x19, 0x24, 0x17,
538	0x54, 0x1f, 0x44, 0x80, 0xff, 0x22, 0x74, 0x2a, 0x25, 0x19, 0xf8, 0xe6,
539	0x22, 0x12, 0x46, 0x72, 0x12, 0x46, 0x68, 0x90, 0x47, 0xfa, 0xe0, 0x54,
540	0xf8, 0x44, 0x02, 0xf0, 0x22, 0xe5, 0x7e, 0xae, 0x7d, 0x78, 0x04, 0x22,
541	0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0x22, 0xe4, 0x78, 0xc4, 0xf6, 0xc2,
542	0x0d, 0x78, 0xc1, 0xf6, 0x22, 0xc2, 0x0c, 0xc2, 0x0b, 0x22, 0x22,
543};
544
545static const u8 fw_patch_vsc8584[] = {
546	0xe8, 0x59, 0x02, 0xe8, 0x12, 0x02, 0xe8, 0x42, 0x02, 0xe8, 0x5a, 0x02,
547	0xe8, 0x5b, 0x02, 0xe8, 0x5c, 0xe5, 0x69, 0x54, 0x0f, 0x24, 0xf7, 0x60,
548	0x27, 0x24, 0xfc, 0x60, 0x23, 0x24, 0x08, 0x70, 0x14, 0xe5, 0x69, 0xae,
549	0x68, 0x78, 0x04, 0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0xd8, 0xf8, 0x7e,
550	0x00, 0x54, 0x0f, 0x80, 0x00, 0x7b, 0x01, 0x7a, 0x00, 0x7d, 0xee, 0x7f,
551	0x92, 0x12, 0x50, 0xee, 0x22, 0xe4, 0xf5, 0x10, 0x85, 0x10, 0xfb, 0x7d,
552	0x1c, 0xe4, 0xff, 0x12, 0x59, 0xea, 0x05, 0x10, 0xe5, 0x10, 0xc3, 0x94,
553	0x04, 0x40, 0xed, 0x22, 0x22, 0x22, 0x22, 0x22,
554};
555
556static int vsc8584_get_fw_crc(struct mii_dev *bus, int phy, u16 start,
557			      u16 *crc, const u8 *fw_patch, int fw_size)
558{
559	int ret;
560
561	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
562		   MSCC_PHY_PAGE_EXT1);
563
564	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_VERIPHY_CNTL_2, start);
565	/* Add one byte to size for the one added by the patch_fw function */
566	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_VERIPHY_CNTL_3,
567		   fw_size + 1);
568
569	ret = vsc8584_cmd(bus, phy, PROC_CMD_CRC16);
570	if (ret)
571		goto out;
572
573	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
574		   MSCC_PHY_PAGE_EXT1);
575
576	*crc = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_VERIPHY_CNTL_2);
577
578out:
579	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
580		   MSCC_PHY_PAGE_STD);
581
582	return ret;
583}
584
585static int vsc8584_patch_fw(struct mii_dev *bus, int phy, const u8 *fw_patch,
586			    int fw_size)
587{
588	int i, ret;
589
590	ret = vsc8584_micro_assert_reset(bus, phy);
591	if (ret) {
592		pr_err("%s: failed to assert reset of micro\n", __func__);
593		return ret;
594	}
595
596	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
597		   MSCC_PHY_PAGE_GPIO);
598
599	/*
600	 * Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
601	 * Disable the 8051 Micro clock
602	 */
603	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS,
604		   RUN_FROM_INT_ROM | AUTOINC_ADDR | PATCH_RAM_CLK |
605		   MICRO_CLK_EN | MICRO_CLK_DIVIDE(2));
606	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, READ_PRAM |
607		   INT_MEM_WRITE_EN | INT_MEM_DATA(2));
608	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_ADDR, 0x0000);
609
610	for (i = 0; i < fw_size; i++)
611		bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL,
612			   READ_PRAM | INT_MEM_WRITE_EN | fw_patch[i]);
613
614	/* Clear internal memory access */
615	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, READ_RAM);
616
617	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
618		   MSCC_PHY_PAGE_STD);
619
620	return 0;
621}
622
623static bool vsc8574_is_serdes_init(struct mii_dev *bus, int phy)
624{
625	u16 reg;
626	bool ret;
627
628	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
629		   MSCC_PHY_PAGE_GPIO);
630
631	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_TRAP_ROM_ADDR(1));
632	if (reg != MSCC_TRAP_ROM_ADDR_SERDES_INIT) {
633		ret = false;
634		goto out;
635	}
636
637	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_PATCH_RAM_ADDR(1));
638	if (reg != MSCC_PATCH_RAM_ADDR_SERDES_INIT) {
639		ret = false;
640		goto out;
641	}
642
643	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
644	if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
645		ret = false;
646		goto out;
647	}
648
649	reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS);
650	if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM |  DW8051_CLK_EN |
651	     MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
652		ret = false;
653		goto out;
654	}
655
656	ret = true;
657
658out:
659	bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
660		   MSCC_PHY_PAGE_GPIO);
661
662	return ret;
663}
664
665static int vsc8574_config_pre_init(struct phy_device *phydev)
666{
667	struct mii_dev *bus = phydev->bus;
668	u16 crc, reg, phy0, addr;
669	bool serdes_init;
670	int ret;
671
672	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
673		  MSCC_PHY_PAGE_EXT1);
674	addr = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_4);
675	addr >>= PHY_CNTL_4_ADDR_POS;
676
677	reg = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_ACTIPHY_CNTL);
678	if (reg & PHY_ADDR_REVERSED)
679		phy0 = phydev->addr + addr;
680	else
681		phy0 = phydev->addr - addr;
682
683	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
684		   MSCC_PHY_PAGE_STD);
685
686	/* all writes below are broadcasted to all PHYs in the same package */
687	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
688	reg |= SMI_BROADCAST_WR_EN;
689	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
690
691	/*
692	 * The below register writes are tweaking analog and electrical
693	 * configuration that were determined through characterization by PHY
694	 * engineers. These don't mean anything more than "these are the best
695	 * values".
696	 */
697	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
698
699	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
700		   MSCC_PHY_PAGE_TEST);
701
702	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_20, 0x4320);
703	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_24, 0x0c00);
704	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_9, 0x18ca);
705	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_5, 0x1b20);
706
707	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
708	reg |= TR_CLK_DISABLE;
709	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
710
711	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
712		   MSCC_PHY_PAGE_TR);
713
714	vsc8584_csr_write(bus, phy0, 0x0fae, 0x000401bd);
715	vsc8584_csr_write(bus, phy0, 0x0fac, 0x000f000f);
716	vsc8584_csr_write(bus, phy0, 0x17a0, 0x00a0f147);
717	vsc8584_csr_write(bus, phy0, 0x0fe4, 0x00052f54);
718	vsc8584_csr_write(bus, phy0, 0x1792, 0x0027303d);
719	vsc8584_csr_write(bus, phy0, 0x07fe, 0x00000704);
720	vsc8584_csr_write(bus, phy0, 0x0fe0, 0x00060150);
721	vsc8584_csr_write(bus, phy0, 0x0f82, 0x0012b00a);
722	vsc8584_csr_write(bus, phy0, 0x0f80, 0x00000d74);
723	vsc8584_csr_write(bus, phy0, 0x02e0, 0x00000012);
724	vsc8584_csr_write(bus, phy0, 0x03a2, 0x00050208);
725	vsc8584_csr_write(bus, phy0, 0x03b2, 0x00009186);
726	vsc8584_csr_write(bus, phy0, 0x0fb0, 0x000e3700);
727	vsc8584_csr_write(bus, phy0, 0x1688, 0x00049f81);
728	vsc8584_csr_write(bus, phy0, 0x0fd2, 0x0000ffff);
729	vsc8584_csr_write(bus, phy0, 0x168a, 0x00039fa2);
730	vsc8584_csr_write(bus, phy0, 0x1690, 0x0020640b);
731	vsc8584_csr_write(bus, phy0, 0x0258, 0x00002220);
732	vsc8584_csr_write(bus, phy0, 0x025a, 0x00002a20);
733	vsc8584_csr_write(bus, phy0, 0x025c, 0x00003060);
734	vsc8584_csr_write(bus, phy0, 0x025e, 0x00003fa0);
735	vsc8584_csr_write(bus, phy0, 0x03a6, 0x0000e0f0);
736	vsc8584_csr_write(bus, phy0, 0x0f92, 0x00001489);
737	vsc8584_csr_write(bus, phy0, 0x16a2, 0x00007000);
738	vsc8584_csr_write(bus, phy0, 0x16a6, 0x00071448);
739	vsc8584_csr_write(bus, phy0, 0x16a0, 0x00eeffdd);
740	vsc8584_csr_write(bus, phy0, 0x0fe8, 0x0091b06c);
741	vsc8584_csr_write(bus, phy0, 0x0fea, 0x00041600);
742	vsc8584_csr_write(bus, phy0, 0x16b0, 0x00eeff00);
743	vsc8584_csr_write(bus, phy0, 0x16b2, 0x00007000);
744	vsc8584_csr_write(bus, phy0, 0x16b4, 0x00000814);
745	vsc8584_csr_write(bus, phy0, 0x0f90, 0x00688980);
746	vsc8584_csr_write(bus, phy0, 0x03a4, 0x0000d8f0);
747	vsc8584_csr_write(bus, phy0, 0x0fc0, 0x00000400);
748	vsc8584_csr_write(bus, phy0, 0x07fa, 0x0050100f);
749	vsc8584_csr_write(bus, phy0, 0x0796, 0x00000003);
750	vsc8584_csr_write(bus, phy0, 0x07f8, 0x00c3ff98);
751	vsc8584_csr_write(bus, phy0, 0x0fa4, 0x0018292a);
752	vsc8584_csr_write(bus, phy0, 0x168c, 0x00d2c46f);
753	vsc8584_csr_write(bus, phy0, 0x17a2, 0x00000620);
754	vsc8584_csr_write(bus, phy0, 0x16a4, 0x0013132f);
755	vsc8584_csr_write(bus, phy0, 0x16a8, 0x00000000);
756	vsc8584_csr_write(bus, phy0, 0x0ffc, 0x00c0a028);
757	vsc8584_csr_write(bus, phy0, 0x0fec, 0x00901c09);
758	vsc8584_csr_write(bus, phy0, 0x0fee, 0x0004a6a1);
759	vsc8584_csr_write(bus, phy0, 0x0ffe, 0x00b01807);
760
761	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
762			MSCC_PHY_PAGE_EXT2);
763
764	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
765
766	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
767		   MSCC_PHY_PAGE_TR);
768
769	vsc8584_csr_write(bus, phy0, 0x0486, 0x0008a518);
770	vsc8584_csr_write(bus, phy0, 0x0488, 0x006dc696);
771	vsc8584_csr_write(bus, phy0, 0x048a, 0x00000912);
772	vsc8584_csr_write(bus, phy0, 0x048e, 0x00000db6);
773	vsc8584_csr_write(bus, phy0, 0x049c, 0x00596596);
774	vsc8584_csr_write(bus, phy0, 0x049e, 0x00000514);
775	vsc8584_csr_write(bus, phy0, 0x04a2, 0x00410280);
776	vsc8584_csr_write(bus, phy0, 0x04a4, 0x00000000);
777	vsc8584_csr_write(bus, phy0, 0x04a6, 0x00000000);
778	vsc8584_csr_write(bus, phy0, 0x04a8, 0x00000000);
779	vsc8584_csr_write(bus, phy0, 0x04aa, 0x00000000);
780	vsc8584_csr_write(bus, phy0, 0x04ae, 0x007df7dd);
781	vsc8584_csr_write(bus, phy0, 0x04b0, 0x006d95d4);
782	vsc8584_csr_write(bus, phy0, 0x04b2, 0x00492410);
783
784	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
785		   MSCC_PHY_PAGE_TEST);
786
787	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
788	reg &= ~TR_CLK_DISABLE;
789	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
790
791	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
792			MSCC_PHY_PAGE_STD);
793
794	/* end of write broadcasting */
795	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
796	reg &= ~SMI_BROADCAST_WR_EN;
797	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
798
799	ret = vsc8584_get_fw_crc(bus, phy0,
800				 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR, &crc,
801				 fw_patch_vsc8574,
802				 ARRAY_SIZE(fw_patch_vsc8574));
803	if (ret)
804		goto out;
805
806	if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
807		serdes_init = vsc8574_is_serdes_init(bus, phy0);
808
809		if (!serdes_init) {
810			ret = vsc8584_micro_assert_reset(bus, phy0);
811			if (ret) {
812				pr_err("failed to assert reset of micro\n");
813				return ret;
814			}
815		}
816	} else {
817		pr_debug("FW CRC is not the expected one, patching FW\n");
818
819		serdes_init = false;
820
821		if (vsc8584_patch_fw(bus, phy0, fw_patch_vsc8574,
822				     ARRAY_SIZE(fw_patch_vsc8574)))
823			pr_warn("failed to patch FW, expect non-optimal device\n");
824	}
825
826	if (!serdes_init) {
827		bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
828				MSCC_PHY_PAGE_GPIO);
829
830		bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_TRAP_ROM_ADDR(1),
831			   MSCC_TRAP_ROM_ADDR_SERDES_INIT);
832		bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PATCH_RAM_ADDR(1),
833			   MSCC_PATCH_RAM_ADDR_SERDES_INIT);
834
835		bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL,
836				EN_PATCH_RAM_TRAP_ADDR(1));
837
838		vsc8584_micro_deassert_reset(bus, phy0, false);
839
840		ret = vsc8584_get_fw_crc(bus, phy0,
841					 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
842					 &crc, fw_patch_vsc8574,
843					 ARRAY_SIZE(fw_patch_vsc8574));
844		if (ret)
845			goto out;
846
847		if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
848			pr_warn("FW CRC after patching is not the expected one, expect non-optimal device\n");
849	}
850
851	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
852		   MSCC_PHY_PAGE_GPIO);
853
854	ret = vsc8584_cmd(bus, phy0, PROC_CMD_1588_DEFAULT_INIT |
855			  PROC_CMD_PHY_INIT);
856
857out:
858	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
859			MSCC_PHY_PAGE_STD);
860
861	return ret;
862}
863
864static int vsc8584_config_pre_init(struct phy_device *phydev)
865{
866	struct mii_dev *bus = phydev->bus;
867	u16 reg, crc, phy0, addr;
868	int ret;
869
870	if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
871		pr_warn("VSC8584 revA not officially supported, skipping firmware patching. Use at your own risk.\n");
872		return 0;
873	}
874
875	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
876		  MSCC_PHY_PAGE_EXT1);
877	addr = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_4);
878	addr >>= PHY_CNTL_4_ADDR_POS;
879
880	reg = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_ACTIPHY_CNTL);
881	if (reg & PHY_ADDR_REVERSED)
882		phy0 = phydev->addr + addr;
883	else
884		phy0 = phydev->addr - addr;
885
886	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
887		   MSCC_PHY_PAGE_STD);
888
889	/* all writes below are broadcasted to all PHYs in the same package */
890	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
891	reg |= SMI_BROADCAST_WR_EN;
892	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
893
894	/*
895	 * The below register writes are tweaking analog and electrical
896	 * configuration that were determined through characterization by PHY
897	 * engineers. These don't mean anything more than "these are the best
898	 * values".
899	 */
900	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_BYPASS_CONTROL);
901	reg |= PARALLEL_DET_IGNORE_ADVERTISED;
902	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_BYPASS_CONTROL, reg);
903
904	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
905		   MSCC_PHY_PAGE_EXT3);
906
907	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_SERDES_TX_CRC_ERR_CNT,
908		   0x2000);
909
910	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
911		   MSCC_PHY_PAGE_TEST);
912
913	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_5, 0x1f20);
914
915	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
916	reg |= TR_CLK_DISABLE;
917	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
918
919	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
920		   MSCC_PHY_PAGE_TR);
921
922	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, 0xafa4);
923
924	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
925	reg &= ~0x007f;
926	reg |= 0x0019;
927	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg);
928
929	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, 0x8fa4);
930
931	vsc8584_csr_write(bus, phy0, 0x07fa, 0x0050100f);
932	vsc8584_csr_write(bus, phy0, 0x1688, 0x00049f81);
933	vsc8584_csr_write(bus, phy0, 0x0f90, 0x00688980);
934	vsc8584_csr_write(bus, phy0, 0x03a4, 0x0000d8f0);
935	vsc8584_csr_write(bus, phy0, 0x0fc0, 0x00000400);
936	vsc8584_csr_write(bus, phy0, 0x0f82, 0x0012b002);
937	vsc8584_csr_write(bus, phy0, 0x1686, 0x00000004);
938	vsc8584_csr_write(bus, phy0, 0x168c, 0x00d2c46f);
939	vsc8584_csr_write(bus, phy0, 0x17a2, 0x00000620);
940	vsc8584_csr_write(bus, phy0, 0x16a0, 0x00eeffdd);
941	vsc8584_csr_write(bus, phy0, 0x16a6, 0x00071448);
942	vsc8584_csr_write(bus, phy0, 0x16a4, 0x0013132f);
943	vsc8584_csr_write(bus, phy0, 0x16a8, 0x00000000);
944	vsc8584_csr_write(bus, phy0, 0x0ffc, 0x00c0a028);
945	vsc8584_csr_write(bus, phy0, 0x0fe8, 0x0091b06c);
946	vsc8584_csr_write(bus, phy0, 0x0fea, 0x00041600);
947	vsc8584_csr_write(bus, phy0, 0x0f80, 0x00fffaff);
948	vsc8584_csr_write(bus, phy0, 0x0fec, 0x00901809);
949	vsc8584_csr_write(bus, phy0, 0x0ffe, 0x00b01007);
950	vsc8584_csr_write(bus, phy0, 0x16b0, 0x00eeff00);
951	vsc8584_csr_write(bus, phy0, 0x16b2, 0x00007000);
952	vsc8584_csr_write(bus, phy0, 0x16b4, 0x00000814);
953
954	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
955		   MSCC_PHY_PAGE_EXT2);
956
957	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
958
959	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
960		   MSCC_PHY_PAGE_TR);
961
962	vsc8584_csr_write(bus, phy0, 0x0486, 0x0008a518);
963	vsc8584_csr_write(bus, phy0, 0x0488, 0x006dc696);
964	vsc8584_csr_write(bus, phy0, 0x048a, 0x00000912);
965
966	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
967		   MSCC_PHY_PAGE_TEST);
968
969	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
970	reg &= ~TR_CLK_DISABLE;
971	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
972
973	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
974		   MSCC_PHY_PAGE_STD);
975
976	/* end of write broadcasting */
977	reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
978	reg &= ~SMI_BROADCAST_WR_EN;
979	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
980
981	ret = vsc8584_get_fw_crc(bus, phy0,
982				 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR, &crc,
983				 fw_patch_vsc8584,
984				 ARRAY_SIZE(fw_patch_vsc8584));
985	if (ret)
986		goto out;
987
988	if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
989		debug("FW CRC is not the expected one, patching FW...\n");
990		if (vsc8584_patch_fw(bus, phy0, fw_patch_vsc8584,
991				     ARRAY_SIZE(fw_patch_vsc8584)))
992			pr_warn("failed to patch FW, expect non-optimal device\n");
993	}
994
995	vsc8584_micro_deassert_reset(bus, phy0, false);
996
997	ret = vsc8584_get_fw_crc(bus, phy0,
998				 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR, &crc,
999				 fw_patch_vsc8584,
1000				 ARRAY_SIZE(fw_patch_vsc8584));
1001	if (ret)
1002		goto out;
1003
1004	if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
1005		pr_warn("FW CRC after patching is not the expected one, expect non-optimal device\n");
1006
1007	ret = vsc8584_micro_assert_reset(bus, phy0);
1008	if (ret)
1009		goto out;
1010
1011	vsc8584_micro_deassert_reset(bus, phy0, true);
1012
1013out:
1014	bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1015		   MSCC_PHY_PAGE_STD);
1016
1017	return ret;
1018}
1019
1020static int mscc_vsc8531_vsc8541_init_scripts(struct phy_device *phydev)
1021{
1022	u16	reg_val;
1023
1024	/* Set to Access Token Ring Registers */
1025	phy_write(phydev, MDIO_DEVAD_NONE,
1026		  MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
1027
1028	/* Update LinkDetectCtrl default to optimized values */
1029	/* Determined during Silicon Validation Testing */
1030	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
1031		  (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_READ));
1032	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
1033	reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_LINKDETCTRL_POS,
1034				   MSCC_PHY_TR_LINKDETCTRL_WIDTH,
1035				   MSCC_PHY_TR_LINKDETCTRL_VAL);
1036
1037	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
1038	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
1039		  (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_WRITE));
1040
1041	/* Update VgaThresh100 defaults to optimized values */
1042	/* Determined during Silicon Validation Testing */
1043	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
1044		  (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_READ));
1045
1046	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
1047	reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGATHRESH100_POS,
1048				   MSCC_PHY_TR_VGATHRESH100_WIDTH,
1049				   MSCC_PHY_TR_VGATHRESH100_VAL);
1050
1051	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
1052	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
1053		  (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_WRITE));
1054
1055	/* Update VgaGain10 defaults to optimized values */
1056	/* Determined during Silicon Validation Testing */
1057	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
1058		  (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_READ));
1059
1060	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
1061	reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_U_POS,
1062				   MSCC_PHY_TR_VGAGAIN10_U_WIDTH,
1063				   MSCC_PHY_TR_VGAGAIN10_U_VAL);
1064
1065	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
1066	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
1067	reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_L_POS,
1068				   MSCC_PHY_TR_VGAGAIN10_L_WIDTH,
1069				   MSCC_PHY_TR_VGAGAIN10_L_VAL);
1070
1071	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
1072	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
1073		  (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_WRITE));
1074
1075	/* Set back to Access Standard Page Registers */
1076	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1077		  MSCC_PHY_PAGE_STD);
1078
1079	return 0;
1080}
1081
1082static int mscc_parse_status(struct phy_device *phydev)
1083{
1084	u16 speed;
1085	u16 mii_reg;
1086
1087	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_AUX_CNTRL_STAT_REG);
1088
1089	if (mii_reg & MIIM_AUX_CNTRL_STAT_F_DUPLEX)
1090		phydev->duplex = DUPLEX_FULL;
1091	else
1092		phydev->duplex = DUPLEX_HALF;
1093
1094	speed = mii_reg & MIIM_AUX_CNTRL_STAT_SPEED_MASK;
1095	speed = speed >> MIIM_AUX_CNTRL_STAT_SPEED_POS;
1096
1097	switch (speed) {
1098	case MIIM_AUX_CNTRL_STAT_SPEED_1000M:
1099		phydev->speed = SPEED_1000;
1100		break;
1101	case MIIM_AUX_CNTRL_STAT_SPEED_100M:
1102		phydev->speed = SPEED_100;
1103		break;
1104	case MIIM_AUX_CNTRL_STAT_SPEED_10M:
1105		phydev->speed = SPEED_10;
1106		break;
1107	default:
1108		phydev->speed = SPEED_10;
1109		break;
1110	}
1111
1112	return 0;
1113}
1114
1115static int mscc_startup(struct phy_device *phydev)
1116{
1117	int retval;
1118
1119	retval = genphy_update_link(phydev);
1120
1121	if (retval)
1122		return retval;
1123
1124	return mscc_parse_status(phydev);
1125}
1126
1127static int mscc_phy_soft_reset(struct phy_device *phydev)
1128{
1129	int     retval = 0;
1130	u16     timeout = MSCC_PHY_RESET_TIMEOUT;
1131	u16     reg_val = 0;
1132
1133	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1134		  MSCC_PHY_PAGE_STD);
1135
1136	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
1137	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (reg_val | BMCR_RESET));
1138
1139	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
1140
1141	while ((reg_val & BMCR_RESET) && (timeout > 0)) {
1142		reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
1143		timeout--;
1144		udelay(1000);   /* 1 ms */
1145	}
1146
1147	if (timeout == 0) {
1148		printf("MSCC PHY Soft_Reset Error: mac i/f = 0x%x\n",
1149		       phydev->interface);
1150		retval = -ETIME;
1151	}
1152
1153	return retval;
1154}
1155
1156static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
1157{
1158	u16	reg_val = 0;
1159	u16	mac_if = 0;
1160	u16	rx_clk_out = 0;
1161
1162	/* For VSC8530/31 the only MAC modes are RMII/RGMII. */
1163	/* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
1164	/* Setup MAC Configuration */
1165	switch (phydev->interface) {
1166	case PHY_INTERFACE_MODE_MII:
1167	case PHY_INTERFACE_MODE_GMII:
1168		/* Set Reg23.12:11=0 */
1169		mac_if = MAC_IF_SELECTION_GMII;
1170		/* Set Reg20E2.11=1 */
1171		rx_clk_out = RX_CLK_OUT_DISABLE;
1172		break;
1173
1174	case PHY_INTERFACE_MODE_RMII:
1175		/* Set Reg23.12:11=1 */
1176		mac_if = MAC_IF_SELECTION_RMII;
1177		/* Set Reg20E2.11=0 */
1178		rx_clk_out = RX_CLK_OUT_NORMAL;
1179		break;
1180
1181	case PHY_INTERFACE_MODE_RGMII_TXID:
1182	case PHY_INTERFACE_MODE_RGMII_RXID:
1183	case PHY_INTERFACE_MODE_RGMII_ID:
1184	case PHY_INTERFACE_MODE_RGMII:
1185		/* Set Reg23.12:11=2 */
1186		mac_if = MAC_IF_SELECTION_RGMII;
1187		/* Set Reg20E2.11=0 */
1188		rx_clk_out = RX_CLK_OUT_NORMAL;
1189		break;
1190
1191	default:
1192		printf("MSCC PHY - INVALID MAC i/f Config: mac i/f = 0x%x\n",
1193		       phydev->interface);
1194		return -EINVAL;
1195	}
1196
1197	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1198		  MSCC_PHY_PAGE_STD);
1199
1200	reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
1201			   MSCC_PHY_EXT_PHY_CNTL_1_REG);
1202	/* Set MAC i/f bits Reg23.12:11 */
1203	reg_val = bitfield_replace(reg_val, MAC_IF_SELECTION_POS,
1204				   MAC_IF_SELECTION_WIDTH, mac_if);
1205	/* Update Reg23.12:11 */
1206	phy_write(phydev, MDIO_DEVAD_NONE,
1207		  MSCC_PHY_EXT_PHY_CNTL_1_REG, reg_val);
1208	/* Setup ExtPg_2 Register Access */
1209	phy_write(phydev, MDIO_DEVAD_NONE,
1210		  MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2);
1211	/* Read Reg20E2 */
1212	reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
1213			   MSCC_PHY_RGMII_CNTL_REG);
1214	reg_val = bitfield_replace(reg_val, RX_CLK_OUT_POS,
1215				   RX_CLK_OUT_WIDTH, rx_clk_out);
1216	/* Update Reg20E2.11 */
1217	phy_write(phydev, MDIO_DEVAD_NONE,
1218		  MSCC_PHY_RGMII_CNTL_REG, reg_val);
1219	/* Before leaving - Change back to Std Page Register Access */
1220	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1221		  MSCC_PHY_PAGE_STD);
1222
1223	return 0;
1224}
1225
1226static int vsc8531_vsc8541_clkout_config(struct phy_device *phydev)
1227{
1228	struct ofnode_phandle_args phandle_args;
1229	u32 clkout_rate = 0;
1230	u16 reg_val;
1231	int retval;
1232
1233	retval = dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL,
1234					    0, 0, &phandle_args);
1235	if (!retval)
1236		clkout_rate = ofnode_read_u32_default(phandle_args.node,
1237						"vsc8531,clk-out-frequency", 0);
1238
1239	switch (clkout_rate) {
1240	case 0:
1241		reg_val = 0;
1242		break;
1243	case 25000000:
1244		reg_val = CLKOUT_FREQ_25M | CLKOUT_ENABLE;
1245		break;
1246	case 50000000:
1247		reg_val = CLKOUT_FREQ_50M | CLKOUT_ENABLE;
1248		break;
1249	case 125000000:
1250		reg_val = CLKOUT_FREQ_125M | CLKOUT_ENABLE;
1251		break;
1252	default:
1253		printf("PHY 8530/31 invalid clkout rate %u\n",
1254		       clkout_rate);
1255		return -EINVAL;
1256	}
1257
1258	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1259		  MSCC_PHY_PAGE_GPIO);
1260	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_CLKOUT_CNTL, reg_val);
1261	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1262		  MSCC_PHY_PAGE_STD);
1263
1264	return 0;
1265}
1266
1267static int vsc8531_vsc8541_clk_skew_config(struct phy_device *phydev)
1268{
1269	enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS;
1270	enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS;
1271	u16 reg_val;
1272
1273	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
1274	    phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
1275		rx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS;
1276
1277	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
1278	    phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
1279		tx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS;
1280
1281	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1282		  MSCC_PHY_PAGE_EXT2);
1283	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
1284
1285	/* Reg20E2 - Update RGMII RX_Clk Skews. */
1286	reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
1287				   RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
1288	/* Reg20E2 - Update RGMII TX_Clk Skews. */
1289	reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
1290				   RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
1291
1292	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
1293	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1294		  MSCC_PHY_PAGE_STD);
1295
1296	return 0;
1297}
1298
1299static int vsc8531_config(struct phy_device *phydev)
1300{
1301	int  retval = -EINVAL;
1302	u16  reg_val;
1303	u16  rmii_clk_out;
1304	enum vsc_phy_clk_slew    edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
1305
1306	/* For VSC8530/31 and VSC8540/41 the init scripts are the same */
1307	mscc_vsc8531_vsc8541_init_scripts(phydev);
1308
1309	/* For VSC8530/31 the only MAC modes are RMII/RGMII. */
1310	switch (phydev->interface) {
1311	case PHY_INTERFACE_MODE_RMII:
1312	case PHY_INTERFACE_MODE_RGMII:
1313	case PHY_INTERFACE_MODE_RGMII_TXID:
1314	case PHY_INTERFACE_MODE_RGMII_RXID:
1315	case PHY_INTERFACE_MODE_RGMII_ID:
1316		retval = vsc8531_vsc8541_mac_config(phydev);
1317		if (retval != 0)
1318			return retval;
1319
1320		retval = mscc_phy_soft_reset(phydev);
1321		if (retval != 0)
1322			return retval;
1323		break;
1324	default:
1325		printf("PHY 8530/31 MAC i/f Config Error: mac i/f = 0x%x\n",
1326		       phydev->interface);
1327		return -EINVAL;
1328	}
1329	/* Default RMII Clk Output to 0=OFF/1=ON  */
1330	rmii_clk_out = 0;
1331
1332	retval = vsc8531_vsc8541_clk_skew_config(phydev);
1333	if (retval != 0)
1334		return retval;
1335
1336	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1337		  MSCC_PHY_PAGE_EXT2);
1338	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
1339	/* Reg27E2 - Update Clk Slew Rate. */
1340	reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
1341				   EDGE_RATE_CNTL_WIDTH, edge_rate);
1342	/* Reg27E2 - Update RMII Clk Out. */
1343	reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
1344				   RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
1345	/* Update Reg27E2 */
1346	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
1347	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1348		  MSCC_PHY_PAGE_STD);
1349
1350	/* Configure the clk output */
1351	retval = vsc8531_vsc8541_clkout_config(phydev);
1352	if (retval != 0)
1353		return retval;
1354
1355	return genphy_config_aneg(phydev);
1356}
1357
1358static int vsc8541_config(struct phy_device *phydev)
1359{
1360	int  retval = -EINVAL;
1361	u16  reg_val;
1362	u16  rmii_clk_out;
1363	enum vsc_phy_clk_slew    edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
1364
1365	/* For VSC8530/31 and VSC8540/41 the init scripts are the same */
1366	mscc_vsc8531_vsc8541_init_scripts(phydev);
1367
1368	/* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
1369	switch (phydev->interface) {
1370	case PHY_INTERFACE_MODE_MII:
1371	case PHY_INTERFACE_MODE_GMII:
1372	case PHY_INTERFACE_MODE_RMII:
1373	case PHY_INTERFACE_MODE_RGMII:
1374		retval = vsc8531_vsc8541_mac_config(phydev);
1375		if (retval != 0)
1376			return retval;
1377
1378		retval = mscc_phy_soft_reset(phydev);
1379		if (retval != 0)
1380			return retval;
1381		break;
1382	default:
1383		printf("PHY 8541 MAC i/f config Error: mac i/f = 0x%x\n",
1384		       phydev->interface);
1385		return -EINVAL;
1386	}
1387	/* Default RMII Clk Output to 0=OFF/1=ON  */
1388	rmii_clk_out = 0;
1389
1390	retval = vsc8531_vsc8541_clk_skew_config(phydev);
1391	if (retval != 0)
1392		return retval;
1393
1394	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1395		  MSCC_PHY_PAGE_EXT2);
1396	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
1397	/* Reg27E2 - Update Clk Slew Rate. */
1398	reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
1399				   EDGE_RATE_CNTL_WIDTH, edge_rate);
1400	/* Reg27E2 - Update RMII Clk Out. */
1401	reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
1402				   RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
1403	/* Update Reg27E2 */
1404	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
1405	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1406		  MSCC_PHY_PAGE_STD);
1407
1408	/* Configure the clk output */
1409	retval = vsc8531_vsc8541_clkout_config(phydev);
1410	if (retval != 0)
1411		return retval;
1412
1413	return genphy_config_aneg(phydev);
1414}
1415
1416static int vsc8584_config_init(struct phy_device *phydev)
1417{
1418	struct vsc85xx_priv *priv = phydev->priv;
1419	int ret;
1420	u16 addr;
1421	u16 reg_val;
1422	u16 val;
1423
1424	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1425		  MSCC_PHY_PAGE_EXT1);
1426	addr = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_4);
1427	addr >>= PHY_CNTL_4_ADDR_POS;
1428
1429	ret = priv->config_pre(phydev);
1430	if (ret)
1431		return ret;
1432
1433	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1434		  MSCC_PHY_PAGE_GPIO);
1435
1436	if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1437		val = MAC_CFG_QSGMII;
1438	else
1439		val = MAC_CFG_SGMII;
1440
1441	reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_MAC_CFG_FASTLINK);
1442	reg_val &= ~MAC_CFG_MASK;
1443	reg_val |= val;
1444	ret = phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_MAC_CFG_FASTLINK,
1445			reg_val);
1446	if (ret)
1447		return ret;
1448
1449	reg_val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
1450		PROC_CMD_READ_MOD_WRITE_PORT;
1451	if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
1452		reg_val |= PROC_CMD_QSGMII_MAC;
1453	else
1454		reg_val |= PROC_CMD_SGMII_MAC;
1455
1456	ret = vsc8584_cmd(phydev->bus, phydev->addr, reg_val);
1457	if (ret)
1458		return ret;
1459
1460	mdelay(10);
1461
1462	/* Disable SerDes for 100Base-FX */
1463	ret = vsc8584_cmd(phydev->bus, phydev->addr, PROC_CMD_FIBER_MEDIA_CONF |
1464			  PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1465			  PROC_CMD_READ_MOD_WRITE_PORT |
1466			  PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
1467	if (ret)
1468		return ret;
1469
1470	/* Disable SerDes for 1000Base-X */
1471	ret = vsc8584_cmd(phydev->bus, phydev->addr, PROC_CMD_FIBER_MEDIA_CONF |
1472			  PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
1473			  PROC_CMD_READ_MOD_WRITE_PORT |
1474			  PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
1475	if (ret)
1476		return ret;
1477
1478	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1479		  MSCC_PHY_PAGE_STD);
1480	reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
1481			   MSCC_PHY_EXT_PHY_CNTL_1_REG);
1482	reg_val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
1483	reg_val |= MEDIA_OP_MODE_COPPER |
1484		(VSC8584_MAC_IF_SELECTION_SGMII <<
1485		 VSC8584_MAC_IF_SELECTION_POS);
1486	ret = phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_1_REG,
1487			reg_val);
1488
1489	ret = mscc_phy_soft_reset(phydev);
1490	if (ret != 0)
1491		return ret;
1492
1493	return genphy_config(phydev);
1494}
1495
1496static struct vsc85xx_priv vsc8574_priv = {
1497	.config_pre = vsc8574_config_pre_init,
1498};
1499
1500static int vsc8574_config(struct phy_device *phydev)
1501{
1502	phydev->priv = &vsc8574_priv;
1503
1504	return vsc8584_config_init(phydev);
1505}
1506
1507static struct vsc85xx_priv vsc8584_priv = {
1508	.config_pre = vsc8584_config_pre_init,
1509};
1510
1511static int vsc8584_config(struct phy_device *phydev)
1512{
1513	phydev->priv = &vsc8584_priv;
1514
1515	return vsc8584_config_init(phydev);
1516}
1517
1518static int vsc8502_config(struct phy_device *phydev)
1519{
1520	bool rgmii_rx_delay = false, rgmii_tx_delay = false;
1521	u16 reg = 0;
1522	int ret;
1523
1524	/* Assume nothing needs to be done for the default GMII/MII mode */
1525	if (!phy_interface_is_rgmii(phydev))
1526		return 0;
1527
1528	/* Set Extended PHY Control 1 register to RGMII */
1529	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_1_REG,
1530		  BIT(13) | BIT(12));
1531
1532	/* Soft reset required after changing PHY mode from the default
1533	 * of GMII/MII
1534	 */
1535	ret = mscc_phy_soft_reset(phydev);
1536	if (ret)
1537		return ret;
1538
1539	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
1540	    phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
1541		rgmii_rx_delay = true;
1542	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
1543	    phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
1544		rgmii_tx_delay = true;
1545
1546	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1547		  MSCC_PHY_PAGE_EXT2);
1548
1549	if (rgmii_rx_delay)
1550		reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_RX_CLK_DELAY_POS;
1551	if (rgmii_tx_delay)
1552		reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_TX_CLK_DELAY_POS;
1553
1554	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg);
1555
1556	phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
1557		  MSCC_PHY_PAGE_STD);
1558
1559	return 0;
1560}
1561
1562U_BOOT_PHY_DRIVER(vsc8530) = {
1563	.name = "Microsemi VSC8530",
1564	.uid = PHY_ID_VSC8530,
1565	.mask = 0x000ffff0,
1566	.features = PHY_BASIC_FEATURES,
1567	.config = &vsc8531_config,
1568	.startup = &mscc_startup,
1569	.shutdown = &genphy_shutdown,
1570};
1571
1572U_BOOT_PHY_DRIVER(vsc8531) = {
1573	.name = "Microsemi VSC8531",
1574	.uid = PHY_ID_VSC8531,
1575	.mask = 0x000ffff0,
1576	.features = PHY_GBIT_FEATURES,
1577	.config = &vsc8531_config,
1578	.startup = &mscc_startup,
1579	.shutdown = &genphy_shutdown,
1580};
1581
1582U_BOOT_PHY_DRIVER(vsc8502) = {
1583	.name = "Microsemi VSC8502",
1584	.uid = PHY_ID_VSC8502,
1585	.mask = 0x000ffff0,
1586	.features = PHY_GBIT_FEATURES,
1587	.config = &vsc8502_config,
1588	.startup = &mscc_startup,
1589	.shutdown = &genphy_shutdown,
1590};
1591
1592U_BOOT_PHY_DRIVER(vsc8540) = {
1593	.name = "Microsemi VSC8540",
1594	.uid = PHY_ID_VSC8540,
1595	.mask = 0x000ffff0,
1596	.features = PHY_BASIC_FEATURES,
1597	.config = &vsc8541_config,
1598	.startup = &mscc_startup,
1599	.shutdown = &genphy_shutdown,
1600};
1601
1602U_BOOT_PHY_DRIVER(vsc8541) = {
1603	.name = "Microsemi VSC8541",
1604	.uid = PHY_ID_VSC8541,
1605	.mask = 0x000ffff0,
1606	.features = PHY_GBIT_FEATURES,
1607	.config = &vsc8541_config,
1608	.startup = &mscc_startup,
1609	.shutdown = &genphy_shutdown,
1610};
1611
1612U_BOOT_PHY_DRIVER(vsc8574) = {
1613	.name = "Microsemi VSC8574",
1614	.uid = PHY_ID_VSC8574,
1615	.mask = 0x000ffff0,
1616	.features = PHY_GBIT_FEATURES,
1617	.config = &vsc8574_config,
1618	.startup = &mscc_startup,
1619	.shutdown = &genphy_shutdown,
1620};
1621
1622U_BOOT_PHY_DRIVER(vsc8584) = {
1623	.name = "Microsemi VSC8584",
1624	.uid = PHY_ID_VSC8584,
1625	.mask = 0x000ffff0,
1626	.features = PHY_GBIT_FEATURES,
1627	.config = &vsc8584_config,
1628	.startup = &mscc_startup,
1629	.shutdown = &genphy_shutdown,
1630};
1631