1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Microsemi PHY drivers
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: The MIT License (MIT)
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (c) 2016 Microsemi Corporation
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Author: John Haechten
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <miiphy.h>
13*4882a593Smuzhiyun #include <bitfield.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun /* Microsemi PHY ID's */
16*4882a593Smuzhiyun #define PHY_ID_VSC8530 0x00070560
17*4882a593Smuzhiyun #define PHY_ID_VSC8531 0x00070570
18*4882a593Smuzhiyun #define PHY_ID_VSC8540 0x00070760
19*4882a593Smuzhiyun #define PHY_ID_VSC8541 0x00070770
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* Microsemi VSC85xx PHY Register Pages */
22*4882a593Smuzhiyun #define MSCC_EXT_PAGE_ACCESS 31 /* Page Access Register */
23*4882a593Smuzhiyun #define MSCC_PHY_PAGE_STD 0x0000 /* Standard registers */
24*4882a593Smuzhiyun #define MSCC_PHY_PAGE_EXT1 0x0001 /* Extended registers - page 1 */
25*4882a593Smuzhiyun #define MSCC_PHY_PAGE_EXT2 0x0002 /* Extended registers - page 2 */
26*4882a593Smuzhiyun #define MSCC_PHY_PAGE_EXT3 0x0003 /* Extended registers - page 3 */
27*4882a593Smuzhiyun #define MSCC_PHY_PAGE_EXT4 0x0004 /* Extended registers - page 4 */
28*4882a593Smuzhiyun #define MSCC_PHY_PAGE_GPIO 0x0010 /* GPIO registers */
29*4882a593Smuzhiyun #define MSCC_PHY_PAGE_TEST 0x2A30 /* TEST Page registers */
30*4882a593Smuzhiyun #define MSCC_PHY_PAGE_TR 0x52B5 /* Token Ring Page registers */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* Std Page Register 28 - PHY AUX Control/Status */
33*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_REG 28
34*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO (0x0004)
35*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_F_DUPLEX (0x0020)
36*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_SPEED_MASK (0x0018)
37*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_SPEED_POS (3)
38*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_SPEED_10M (0x0)
39*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_SPEED_100M (0x1)
40*4882a593Smuzhiyun #define MIIM_AUX_CNTRL_STAT_SPEED_1000M (0x2)
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* Std Page Register 23 - Extended PHY CTRL_1 */
43*4882a593Smuzhiyun #define MSCC_PHY_EXT_PHY_CNTL_1_REG 23
44*4882a593Smuzhiyun #define MAC_IF_SELECTION_MASK (0x1800)
45*4882a593Smuzhiyun #define MAC_IF_SELECTION_GMII (0)
46*4882a593Smuzhiyun #define MAC_IF_SELECTION_RMII (1)
47*4882a593Smuzhiyun #define MAC_IF_SELECTION_RGMII (2)
48*4882a593Smuzhiyun #define MAC_IF_SELECTION_POS (11)
49*4882a593Smuzhiyun #define MAC_IF_SELECTION_WIDTH (2)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* Extended Page 2 Register 20E2 */
52*4882a593Smuzhiyun #define MSCC_PHY_RGMII_CNTL_REG 20
53*4882a593Smuzhiyun #define VSC_FAST_LINK_FAIL2_ENA_MASK (0x8000)
54*4882a593Smuzhiyun #define RX_CLK_OUT_MASK (0x0800)
55*4882a593Smuzhiyun #define RX_CLK_OUT_POS (11)
56*4882a593Smuzhiyun #define RX_CLK_OUT_WIDTH (1)
57*4882a593Smuzhiyun #define RX_CLK_OUT_NORMAL (0)
58*4882a593Smuzhiyun #define RX_CLK_OUT_DISABLE (1)
59*4882a593Smuzhiyun #define RGMII_RX_CLK_DELAY_POS (4)
60*4882a593Smuzhiyun #define RGMII_RX_CLK_DELAY_WIDTH (3)
61*4882a593Smuzhiyun #define RGMII_RX_CLK_DELAY_MASK (0x0070)
62*4882a593Smuzhiyun #define RGMII_TX_CLK_DELAY_POS (0)
63*4882a593Smuzhiyun #define RGMII_TX_CLK_DELAY_WIDTH (3)
64*4882a593Smuzhiyun #define RGMII_TX_CLK_DELAY_MASK (0x0007)
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* Extended Page 2 Register 27E2 */
67*4882a593Smuzhiyun #define MSCC_PHY_WOL_MAC_CONTROL 27
68*4882a593Smuzhiyun #define EDGE_RATE_CNTL_POS (5)
69*4882a593Smuzhiyun #define EDGE_RATE_CNTL_WIDTH (3)
70*4882a593Smuzhiyun #define EDGE_RATE_CNTL_MASK (0x00E0)
71*4882a593Smuzhiyun #define RMII_CLK_OUT_ENABLE_POS (4)
72*4882a593Smuzhiyun #define RMII_CLK_OUT_ENABLE_WIDTH (1)
73*4882a593Smuzhiyun #define RMII_CLK_OUT_ENABLE_MASK (0x10)
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Token Ring Page 0x52B5 Registers */
76*4882a593Smuzhiyun #define MSCC_PHY_REG_TR_ADDR_16 16
77*4882a593Smuzhiyun #define MSCC_PHY_REG_TR_DATA_17 17
78*4882a593Smuzhiyun #define MSCC_PHY_REG_TR_DATA_18 18
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Token Ring - Read Value in */
81*4882a593Smuzhiyun #define MSCC_PHY_TR_16_READ (0xA000)
82*4882a593Smuzhiyun /* Token Ring - Write Value out */
83*4882a593Smuzhiyun #define MSCC_PHY_TR_16_WRITE (0x8000)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* Token Ring Registers */
86*4882a593Smuzhiyun #define MSCC_PHY_TR_LINKDETCTRL_POS (3)
87*4882a593Smuzhiyun #define MSCC_PHY_TR_LINKDETCTRL_WIDTH (2)
88*4882a593Smuzhiyun #define MSCC_PHY_TR_LINKDETCTRL_VAL (3)
89*4882a593Smuzhiyun #define MSCC_PHY_TR_LINKDETCTRL_MASK (0x0018)
90*4882a593Smuzhiyun #define MSCC_PHY_TR_LINKDETCTRL_ADDR (0x07F8)
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun #define MSCC_PHY_TR_VGATHRESH100_POS (0)
93*4882a593Smuzhiyun #define MSCC_PHY_TR_VGATHRESH100_WIDTH (7)
94*4882a593Smuzhiyun #define MSCC_PHY_TR_VGATHRESH100_VAL (0x0018)
95*4882a593Smuzhiyun #define MSCC_PHY_TR_VGATHRESH100_MASK (0x007f)
96*4882a593Smuzhiyun #define MSCC_PHY_TR_VGATHRESH100_ADDR (0x0FA4)
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_U_POS (0)
99*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_U_WIDTH (1)
100*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_U_MASK (0x0001)
101*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_U_VAL (0)
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_L_POS (12)
104*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_L_WIDTH (4)
105*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_L_MASK (0xf000)
106*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_L_VAL (0x0001)
107*4882a593Smuzhiyun #define MSCC_PHY_TR_VGAGAIN10_ADDR (0x0F92)
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* General Timeout Values */
110*4882a593Smuzhiyun #define MSCC_PHY_RESET_TIMEOUT (100)
111*4882a593Smuzhiyun #define MSCC_PHY_MICRO_TIMEOUT (500)
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* RGMII/GMII Clock Delay (Skew) Options */ enum vsc_phy_rgmii_skew {
114*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_200_PS,
115*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_800_PS,
116*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_1100_PS,
117*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_1700_PS,
118*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_2000_PS,
119*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_2300_PS,
120*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_2600_PS,
121*4882a593Smuzhiyun VSC_PHY_RGMII_DELAY_3400_PS,
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* MAC i/f Clock Edge Rage Control (Slew), See Reg27E2 */ enum
125*4882a593Smuzhiyun vsc_phy_clk_slew {
126*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_0,
127*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_1,
128*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_2,
129*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_3,
130*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_4,
131*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_5,
132*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_6,
133*4882a593Smuzhiyun VSC_PHY_CLK_SLEW_RATE_7,
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun
mscc_vsc8531_vsc8541_init_scripts(struct phy_device * phydev)137*4882a593Smuzhiyun static int mscc_vsc8531_vsc8541_init_scripts(struct phy_device *phydev)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun u16 reg_val;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* Set to Access Token Ring Registers */
142*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE,
143*4882a593Smuzhiyun MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /* Update LinkDetectCtrl default to optimized values */
146*4882a593Smuzhiyun /* Determined during Silicon Validation Testing */
147*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
148*4882a593Smuzhiyun (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_READ));
149*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
150*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_LINKDETCTRL_POS,
151*4882a593Smuzhiyun MSCC_PHY_TR_LINKDETCTRL_WIDTH,
152*4882a593Smuzhiyun MSCC_PHY_TR_LINKDETCTRL_VAL);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
155*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
156*4882a593Smuzhiyun (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_WRITE));
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Update VgaThresh100 defaults to optimized values */
159*4882a593Smuzhiyun /* Determined during Silicon Validation Testing */
160*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
161*4882a593Smuzhiyun (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_READ));
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
164*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGATHRESH100_POS,
165*4882a593Smuzhiyun MSCC_PHY_TR_VGATHRESH100_WIDTH,
166*4882a593Smuzhiyun MSCC_PHY_TR_VGATHRESH100_VAL);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
169*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
170*4882a593Smuzhiyun (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_WRITE));
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* Update VgaGain10 defaults to optimized values */
173*4882a593Smuzhiyun /* Determined during Silicon Validation Testing */
174*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
175*4882a593Smuzhiyun (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_READ));
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
178*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_U_POS,
179*4882a593Smuzhiyun MSCC_PHY_TR_VGAGAIN10_U_WIDTH,
180*4882a593Smuzhiyun MSCC_PHY_TR_VGAGAIN10_U_VAL);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
183*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
184*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_L_POS,
185*4882a593Smuzhiyun MSCC_PHY_TR_VGAGAIN10_L_WIDTH,
186*4882a593Smuzhiyun MSCC_PHY_TR_VGAGAIN10_L_VAL);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
189*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
190*4882a593Smuzhiyun (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_WRITE));
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /* Set back to Access Standard Page Registers */
193*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
194*4882a593Smuzhiyun MSCC_PHY_PAGE_STD);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun return 0;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
mscc_parse_status(struct phy_device * phydev)199*4882a593Smuzhiyun static int mscc_parse_status(struct phy_device *phydev)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun u16 speed;
202*4882a593Smuzhiyun u16 mii_reg;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_AUX_CNTRL_STAT_REG);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (mii_reg & MIIM_AUX_CNTRL_STAT_F_DUPLEX)
207*4882a593Smuzhiyun phydev->duplex = DUPLEX_FULL;
208*4882a593Smuzhiyun else
209*4882a593Smuzhiyun phydev->duplex = DUPLEX_HALF;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun speed = mii_reg & MIIM_AUX_CNTRL_STAT_SPEED_MASK;
212*4882a593Smuzhiyun speed = speed >> MIIM_AUX_CNTRL_STAT_SPEED_POS;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun switch (speed) {
215*4882a593Smuzhiyun case MIIM_AUX_CNTRL_STAT_SPEED_1000M:
216*4882a593Smuzhiyun phydev->speed = SPEED_1000;
217*4882a593Smuzhiyun break;
218*4882a593Smuzhiyun case MIIM_AUX_CNTRL_STAT_SPEED_100M:
219*4882a593Smuzhiyun phydev->speed = SPEED_100;
220*4882a593Smuzhiyun break;
221*4882a593Smuzhiyun case MIIM_AUX_CNTRL_STAT_SPEED_10M:
222*4882a593Smuzhiyun phydev->speed = SPEED_10;
223*4882a593Smuzhiyun break;
224*4882a593Smuzhiyun default:
225*4882a593Smuzhiyun phydev->speed = SPEED_10;
226*4882a593Smuzhiyun break;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun return 0;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
mscc_startup(struct phy_device * phydev)232*4882a593Smuzhiyun static int mscc_startup(struct phy_device *phydev)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun int retval;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun retval = genphy_update_link(phydev);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (retval)
239*4882a593Smuzhiyun return retval;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun return mscc_parse_status(phydev);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
mscc_phy_soft_reset(struct phy_device * phydev)244*4882a593Smuzhiyun static int mscc_phy_soft_reset(struct phy_device *phydev)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun int retval = 0;
247*4882a593Smuzhiyun u16 timeout = MSCC_PHY_RESET_TIMEOUT;
248*4882a593Smuzhiyun u16 reg_val = 0;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
251*4882a593Smuzhiyun MSCC_PHY_PAGE_STD);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
254*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (reg_val | BMCR_RESET));
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun while ((reg_val & BMCR_RESET) && (timeout > 0)) {
259*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
260*4882a593Smuzhiyun timeout--;
261*4882a593Smuzhiyun udelay(1000); /* 1 ms */
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (timeout == 0) {
265*4882a593Smuzhiyun printf("MSCC PHY Soft_Reset Error: mac i/f = 0x%x\n",
266*4882a593Smuzhiyun phydev->interface);
267*4882a593Smuzhiyun retval = -ETIME;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun return retval;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
vsc8531_vsc8541_mac_config(struct phy_device * phydev)273*4882a593Smuzhiyun static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun u16 reg_val = 0;
276*4882a593Smuzhiyun u16 mac_if = 0;
277*4882a593Smuzhiyun u16 rx_clk_out = 0;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* For VSC8530/31 the only MAC modes are RMII/RGMII. */
280*4882a593Smuzhiyun /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
281*4882a593Smuzhiyun /* Setup MAC Configuration */
282*4882a593Smuzhiyun switch (phydev->interface) {
283*4882a593Smuzhiyun case PHY_INTERFACE_MODE_MII:
284*4882a593Smuzhiyun case PHY_INTERFACE_MODE_GMII:
285*4882a593Smuzhiyun /* Set Reg23.12:11=0 */
286*4882a593Smuzhiyun mac_if = MAC_IF_SELECTION_GMII;
287*4882a593Smuzhiyun /* Set Reg20E2.11=1 */
288*4882a593Smuzhiyun rx_clk_out = RX_CLK_OUT_DISABLE;
289*4882a593Smuzhiyun break;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RMII:
292*4882a593Smuzhiyun /* Set Reg23.12:11=1 */
293*4882a593Smuzhiyun mac_if = MAC_IF_SELECTION_RMII;
294*4882a593Smuzhiyun /* Set Reg20E2.11=0 */
295*4882a593Smuzhiyun rx_clk_out = RX_CLK_OUT_NORMAL;
296*4882a593Smuzhiyun break;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII:
299*4882a593Smuzhiyun /* Set Reg23.12:11=2 */
300*4882a593Smuzhiyun mac_if = MAC_IF_SELECTION_RGMII;
301*4882a593Smuzhiyun /* Set Reg20E2.11=0 */
302*4882a593Smuzhiyun rx_clk_out = RX_CLK_OUT_NORMAL;
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun default:
306*4882a593Smuzhiyun printf("MSCC PHY - INVALID MAC i/f Config: mac i/f = 0x%x\n",
307*4882a593Smuzhiyun phydev->interface);
308*4882a593Smuzhiyun return -EINVAL;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
312*4882a593Smuzhiyun MSCC_PHY_PAGE_STD);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
315*4882a593Smuzhiyun MSCC_PHY_EXT_PHY_CNTL_1_REG);
316*4882a593Smuzhiyun /* Set MAC i/f bits Reg23.12:11 */
317*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, MAC_IF_SELECTION_POS,
318*4882a593Smuzhiyun MAC_IF_SELECTION_WIDTH, mac_if);
319*4882a593Smuzhiyun /* Update Reg23.12:11 */
320*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE,
321*4882a593Smuzhiyun MSCC_PHY_EXT_PHY_CNTL_1_REG, reg_val);
322*4882a593Smuzhiyun /* Setup ExtPg_2 Register Access */
323*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE,
324*4882a593Smuzhiyun MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2);
325*4882a593Smuzhiyun /* Read Reg20E2 */
326*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
327*4882a593Smuzhiyun MSCC_PHY_RGMII_CNTL_REG);
328*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RX_CLK_OUT_POS,
329*4882a593Smuzhiyun RX_CLK_OUT_WIDTH, rx_clk_out);
330*4882a593Smuzhiyun /* Update Reg20E2.11 */
331*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE,
332*4882a593Smuzhiyun MSCC_PHY_RGMII_CNTL_REG, reg_val);
333*4882a593Smuzhiyun /* Before leaving - Change back to Std Page Register Access */
334*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
335*4882a593Smuzhiyun MSCC_PHY_PAGE_STD);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun return 0;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
vsc8531_config(struct phy_device * phydev)340*4882a593Smuzhiyun static int vsc8531_config(struct phy_device *phydev)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun int retval = -EINVAL;
343*4882a593Smuzhiyun u16 reg_val;
344*4882a593Smuzhiyun u16 rmii_clk_out;
345*4882a593Smuzhiyun enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
346*4882a593Smuzhiyun enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
347*4882a593Smuzhiyun enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* For VSC8530/31 and VSC8540/41 the init scripts are the same */
350*4882a593Smuzhiyun mscc_vsc8531_vsc8541_init_scripts(phydev);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /* For VSC8530/31 the only MAC modes are RMII/RGMII. */
353*4882a593Smuzhiyun switch (phydev->interface) {
354*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RMII:
355*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII:
356*4882a593Smuzhiyun retval = vsc8531_vsc8541_mac_config(phydev);
357*4882a593Smuzhiyun if (retval != 0)
358*4882a593Smuzhiyun return retval;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun retval = mscc_phy_soft_reset(phydev);
361*4882a593Smuzhiyun if (retval != 0)
362*4882a593Smuzhiyun return retval;
363*4882a593Smuzhiyun break;
364*4882a593Smuzhiyun default:
365*4882a593Smuzhiyun printf("PHY 8530/31 MAC i/f Config Error: mac i/f = 0x%x\n",
366*4882a593Smuzhiyun phydev->interface);
367*4882a593Smuzhiyun return -EINVAL;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun /* Default RMII Clk Output to 0=OFF/1=ON */
370*4882a593Smuzhiyun rmii_clk_out = 0;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
373*4882a593Smuzhiyun MSCC_PHY_PAGE_EXT2);
374*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* Reg20E2 - Update RGMII RX_Clk Skews. */
377*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
378*4882a593Smuzhiyun RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
379*4882a593Smuzhiyun /* Reg20E2 - Update RGMII TX_Clk Skews. */
380*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
381*4882a593Smuzhiyun RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
386*4882a593Smuzhiyun /* Reg27E2 - Update Clk Slew Rate. */
387*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
388*4882a593Smuzhiyun EDGE_RATE_CNTL_WIDTH, edge_rate);
389*4882a593Smuzhiyun /* Reg27E2 - Update RMII Clk Out. */
390*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
391*4882a593Smuzhiyun RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
392*4882a593Smuzhiyun /* Update Reg27E2 */
393*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
394*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
395*4882a593Smuzhiyun MSCC_PHY_PAGE_STD);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun return genphy_config_aneg(phydev);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
vsc8541_config(struct phy_device * phydev)400*4882a593Smuzhiyun static int vsc8541_config(struct phy_device *phydev)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun int retval = -EINVAL;
403*4882a593Smuzhiyun u16 reg_val;
404*4882a593Smuzhiyun u16 rmii_clk_out;
405*4882a593Smuzhiyun enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
406*4882a593Smuzhiyun enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
407*4882a593Smuzhiyun enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* For VSC8530/31 and VSC8540/41 the init scripts are the same */
410*4882a593Smuzhiyun mscc_vsc8531_vsc8541_init_scripts(phydev);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
413*4882a593Smuzhiyun switch (phydev->interface) {
414*4882a593Smuzhiyun case PHY_INTERFACE_MODE_MII:
415*4882a593Smuzhiyun case PHY_INTERFACE_MODE_GMII:
416*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RMII:
417*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII:
418*4882a593Smuzhiyun retval = vsc8531_vsc8541_mac_config(phydev);
419*4882a593Smuzhiyun if (retval != 0)
420*4882a593Smuzhiyun return retval;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun retval = mscc_phy_soft_reset(phydev);
423*4882a593Smuzhiyun if (retval != 0)
424*4882a593Smuzhiyun return retval;
425*4882a593Smuzhiyun break;
426*4882a593Smuzhiyun default:
427*4882a593Smuzhiyun printf("PHY 8541 MAC i/f config Error: mac i/f = 0x%x\n",
428*4882a593Smuzhiyun phydev->interface);
429*4882a593Smuzhiyun return -EINVAL;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun /* Default RMII Clk Output to 0=OFF/1=ON */
432*4882a593Smuzhiyun rmii_clk_out = 0;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
435*4882a593Smuzhiyun MSCC_PHY_PAGE_EXT2);
436*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
437*4882a593Smuzhiyun /* Reg20E2 - Update RGMII RX_Clk Skews. */
438*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
439*4882a593Smuzhiyun RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
440*4882a593Smuzhiyun /* Reg20E2 - Update RGMII TX_Clk Skews. */
441*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
442*4882a593Smuzhiyun RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
443*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
446*4882a593Smuzhiyun /* Reg27E2 - Update Clk Slew Rate. */
447*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
448*4882a593Smuzhiyun EDGE_RATE_CNTL_WIDTH, edge_rate);
449*4882a593Smuzhiyun /* Reg27E2 - Update RMII Clk Out. */
450*4882a593Smuzhiyun reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
451*4882a593Smuzhiyun RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
452*4882a593Smuzhiyun /* Update Reg27E2 */
453*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
454*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
455*4882a593Smuzhiyun MSCC_PHY_PAGE_STD);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun return genphy_config_aneg(phydev);
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun static struct phy_driver VSC8530_driver = {
461*4882a593Smuzhiyun .name = "Microsemi VSC8530",
462*4882a593Smuzhiyun .uid = PHY_ID_VSC8530,
463*4882a593Smuzhiyun .mask = 0x000ffff0,
464*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
465*4882a593Smuzhiyun .config = &vsc8531_config,
466*4882a593Smuzhiyun .startup = &mscc_startup,
467*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
468*4882a593Smuzhiyun };
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun static struct phy_driver VSC8531_driver = {
471*4882a593Smuzhiyun .name = "Microsemi VSC8531",
472*4882a593Smuzhiyun .uid = PHY_ID_VSC8531,
473*4882a593Smuzhiyun .mask = 0x000ffff0,
474*4882a593Smuzhiyun .features = PHY_GBIT_FEATURES,
475*4882a593Smuzhiyun .config = &vsc8531_config,
476*4882a593Smuzhiyun .startup = &mscc_startup,
477*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
478*4882a593Smuzhiyun };
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun static struct phy_driver VSC8540_driver = {
481*4882a593Smuzhiyun .name = "Microsemi VSC8540",
482*4882a593Smuzhiyun .uid = PHY_ID_VSC8540,
483*4882a593Smuzhiyun .mask = 0x000ffff0,
484*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
485*4882a593Smuzhiyun .config = &vsc8541_config,
486*4882a593Smuzhiyun .startup = &mscc_startup,
487*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun static struct phy_driver VSC8541_driver = {
491*4882a593Smuzhiyun .name = "Microsemi VSC8541",
492*4882a593Smuzhiyun .uid = PHY_ID_VSC8541,
493*4882a593Smuzhiyun .mask = 0x000ffff0,
494*4882a593Smuzhiyun .features = PHY_GBIT_FEATURES,
495*4882a593Smuzhiyun .config = &vsc8541_config,
496*4882a593Smuzhiyun .startup = &mscc_startup,
497*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
498*4882a593Smuzhiyun };
499*4882a593Smuzhiyun
phy_mscc_init(void)500*4882a593Smuzhiyun int phy_mscc_init(void)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun phy_register(&VSC8530_driver);
503*4882a593Smuzhiyun phy_register(&VSC8531_driver);
504*4882a593Smuzhiyun phy_register(&VSC8540_driver);
505*4882a593Smuzhiyun phy_register(&VSC8541_driver);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return 0;
508*4882a593Smuzhiyun }
509