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