]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
9082eeac AF |
2 | /* |
3 | * Marvell PHY drivers | |
4 | * | |
9082eeac AF |
5 | * Copyright 2010-2011 Freescale Semiconductor, Inc. |
6 | * author Andy Fleming | |
9082eeac AF |
7 | */ |
8 | #include <config.h> | |
9 | #include <common.h> | |
fbfa1aba | 10 | #include <errno.h> |
9082eeac AF |
11 | #include <phy.h> |
12 | ||
13 | #define PHY_AUTONEGOTIATE_TIMEOUT 5000 | |
14 | ||
68e6ecad PE |
15 | #define MII_MARVELL_PHY_PAGE 22 |
16 | ||
9082eeac AF |
17 | /* 88E1011 PHY Status Register */ |
18 | #define MIIM_88E1xxx_PHY_STATUS 0x11 | |
19 | #define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000 | |
20 | #define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000 | |
21 | #define MIIM_88E1xxx_PHYSTAT_100 0x4000 | |
22 | #define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000 | |
23 | #define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800 | |
24 | #define MIIM_88E1xxx_PHYSTAT_LINK 0x0400 | |
25 | ||
26 | #define MIIM_88E1xxx_PHY_SCR 0x10 | |
27 | #define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060 | |
28 | ||
29 | /* 88E1111 PHY LED Control Register */ | |
30 | #define MIIM_88E1111_PHY_LED_CONTROL 24 | |
31 | #define MIIM_88E1111_PHY_LED_DIRECT 0x4100 | |
32 | #define MIIM_88E1111_PHY_LED_COMBINE 0x411C | |
33 | ||
fa12a08e ZRR |
34 | /* 88E1111 Extended PHY Specific Control Register */ |
35 | #define MIIM_88E1111_PHY_EXT_CR 0x14 | |
36 | #define MIIM_88E1111_RX_DELAY 0x80 | |
37 | #define MIIM_88E1111_TX_DELAY 0x2 | |
38 | ||
39 | /* 88E1111 Extended PHY Specific Status Register */ | |
40 | #define MIIM_88E1111_PHY_EXT_SR 0x1b | |
41 | #define MIIM_88E1111_HWCFG_MODE_MASK 0xf | |
42 | #define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb | |
43 | #define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3 | |
44 | #define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4 | |
45 | #define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9 | |
46 | #define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000 | |
47 | #define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000 | |
48 | ||
49 | #define MIIM_88E1111_COPPER 0 | |
50 | #define MIIM_88E1111_FIBER 1 | |
51 | ||
9082eeac AF |
52 | /* 88E1118 PHY defines */ |
53 | #define MIIM_88E1118_PHY_PAGE 22 | |
54 | #define MIIM_88E1118_PHY_LED_PAGE 3 | |
55 | ||
56 | /* 88E1121 PHY LED Control Register */ | |
57 | #define MIIM_88E1121_PHY_LED_CTRL 16 | |
58 | #define MIIM_88E1121_PHY_LED_PAGE 3 | |
59 | #define MIIM_88E1121_PHY_LED_DEF 0x0030 | |
60 | ||
61 | /* 88E1121 PHY IRQ Enable/Status Register */ | |
62 | #define MIIM_88E1121_PHY_IRQ_EN 18 | |
63 | #define MIIM_88E1121_PHY_IRQ_STATUS 19 | |
64 | ||
65 | #define MIIM_88E1121_PHY_PAGE 22 | |
66 | ||
67 | /* 88E1145 Extended PHY Specific Control Register */ | |
68 | #define MIIM_88E1145_PHY_EXT_CR 20 | |
69 | #define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 | |
70 | #define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 | |
71 | ||
72 | #define MIIM_88E1145_PHY_LED_CONTROL 24 | |
73 | #define MIIM_88E1145_PHY_LED_DIRECT 0x4100 | |
74 | ||
75 | #define MIIM_88E1145_PHY_PAGE 29 | |
76 | #define MIIM_88E1145_PHY_CAL_OV 30 | |
77 | ||
78 | #define MIIM_88E1149_PHY_PAGE 29 | |
79 | ||
aeceec0d SH |
80 | /* 88E1310 PHY defines */ |
81 | #define MIIM_88E1310_PHY_LED_CTRL 16 | |
82 | #define MIIM_88E1310_PHY_IRQ_EN 18 | |
83 | #define MIIM_88E1310_PHY_RGMII_CTRL 21 | |
84 | #define MIIM_88E1310_PHY_PAGE 22 | |
85 | ||
93cc2959 | 86 | /* 88E151x PHY defines */ |
68e6ecad PE |
87 | /* Page 2 registers */ |
88 | #define MIIM_88E151x_PHY_MSCR 21 | |
89 | #define MIIM_88E151x_RGMII_RX_DELAY BIT(5) | |
90 | #define MIIM_88E151x_RGMII_TX_DELAY BIT(4) | |
91 | #define MIIM_88E151x_RGMII_RXTX_DELAY (BIT(5) | BIT(4)) | |
93cc2959 JH |
92 | /* Page 3 registers */ |
93 | #define MIIM_88E151x_LED_FUNC_CTRL 16 | |
94 | #define MIIM_88E151x_LED_FLD_SZ 4 | |
95 | #define MIIM_88E151x_LED0_OFFS (0 * MIIM_88E151x_LED_FLD_SZ) | |
96 | #define MIIM_88E151x_LED1_OFFS (1 * MIIM_88E151x_LED_FLD_SZ) | |
97 | #define MIIM_88E151x_LED0_ACT 3 | |
98 | #define MIIM_88E151x_LED1_100_1000_LINK 6 | |
99 | #define MIIM_88E151x_LED_TIMER_CTRL 18 | |
100 | #define MIIM_88E151x_INT_EN_OFFS 7 | |
101 | /* Page 18 registers */ | |
102 | #define MIIM_88E151x_GENERAL_CTRL 20 | |
103 | #define MIIM_88E151x_MODE_SGMII 1 | |
104 | #define MIIM_88E151x_RESET_OFFS 15 | |
105 | ||
ce27eb9b LM |
106 | static int m88e1xxx_phy_extread(struct phy_device *phydev, int addr, |
107 | int devaddr, int regnum) | |
108 | { | |
109 | int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE); | |
110 | int val; | |
111 | ||
112 | phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr); | |
113 | val = phy_read(phydev, MDIO_DEVAD_NONE, regnum); | |
114 | phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage); | |
115 | ||
116 | return val; | |
117 | } | |
118 | ||
119 | static int m88e1xxx_phy_extwrite(struct phy_device *phydev, int addr, | |
120 | int devaddr, int regnum, u16 val) | |
121 | { | |
122 | int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE); | |
123 | ||
124 | phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr); | |
125 | phy_write(phydev, MDIO_DEVAD_NONE, regnum, val); | |
126 | phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage); | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
9082eeac AF |
131 | /* Marvell 88E1011S */ |
132 | static int m88e1011s_config(struct phy_device *phydev) | |
133 | { | |
134 | /* Reset and configure the PHY */ | |
135 | phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); | |
136 | ||
137 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); | |
138 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); | |
139 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); | |
140 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); | |
141 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); | |
142 | ||
143 | phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); | |
144 | ||
145 | genphy_config_aneg(phydev); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | /* Parse the 88E1011's status register for speed and duplex | |
151 | * information | |
152 | */ | |
ef5e821b | 153 | static int m88e1xxx_parse_status(struct phy_device *phydev) |
9082eeac AF |
154 | { |
155 | unsigned int speed; | |
156 | unsigned int mii_reg; | |
157 | ||
158 | mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); | |
159 | ||
160 | if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && | |
76f11d3a | 161 | !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { |
9082eeac AF |
162 | int i = 0; |
163 | ||
164 | puts("Waiting for PHY realtime link"); | |
165 | while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { | |
166 | /* Timeout reached ? */ | |
167 | if (i > PHY_AUTONEGOTIATE_TIMEOUT) { | |
168 | puts(" TIMEOUT !\n"); | |
169 | phydev->link = 0; | |
ef5e821b | 170 | return -ETIMEDOUT; |
9082eeac AF |
171 | } |
172 | ||
173 | if ((i++ % 1000) == 0) | |
174 | putc('.'); | |
175 | udelay(1000); | |
176 | mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, | |
76f11d3a | 177 | MIIM_88E1xxx_PHY_STATUS); |
9082eeac AF |
178 | } |
179 | puts(" done\n"); | |
76f11d3a | 180 | mdelay(500); /* another 500 ms (results in faster booting) */ |
9082eeac AF |
181 | } else { |
182 | if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) | |
183 | phydev->link = 1; | |
184 | else | |
185 | phydev->link = 0; | |
186 | } | |
187 | ||
188 | if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) | |
189 | phydev->duplex = DUPLEX_FULL; | |
190 | else | |
191 | phydev->duplex = DUPLEX_HALF; | |
192 | ||
193 | speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; | |
194 | ||
195 | switch (speed) { | |
196 | case MIIM_88E1xxx_PHYSTAT_GBIT: | |
197 | phydev->speed = SPEED_1000; | |
198 | break; | |
199 | case MIIM_88E1xxx_PHYSTAT_100: | |
200 | phydev->speed = SPEED_100; | |
201 | break; | |
202 | default: | |
203 | phydev->speed = SPEED_10; | |
204 | break; | |
205 | } | |
206 | ||
207 | return 0; | |
208 | } | |
209 | ||
210 | static int m88e1011s_startup(struct phy_device *phydev) | |
211 | { | |
b733c278 | 212 | int ret; |
9082eeac | 213 | |
b733c278 MS |
214 | ret = genphy_update_link(phydev); |
215 | if (ret) | |
216 | return ret; | |
217 | ||
218 | return m88e1xxx_parse_status(phydev); | |
9082eeac AF |
219 | } |
220 | ||
221 | /* Marvell 88E1111S */ | |
222 | static int m88e1111s_config(struct phy_device *phydev) | |
223 | { | |
224 | int reg; | |
225 | ||
24d98cb4 | 226 | if (phy_interface_is_rgmii(phydev)) { |
fa12a08e | 227 | reg = phy_read(phydev, |
76f11d3a | 228 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); |
fa12a08e | 229 | if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || |
76f11d3a | 230 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) { |
fa12a08e ZRR |
231 | reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); |
232 | } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { | |
233 | reg &= ~MIIM_88E1111_TX_DELAY; | |
234 | reg |= MIIM_88E1111_RX_DELAY; | |
235 | } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { | |
236 | reg &= ~MIIM_88E1111_RX_DELAY; | |
237 | reg |= MIIM_88E1111_TX_DELAY; | |
238 | } | |
239 | ||
240 | phy_write(phydev, | |
76f11d3a | 241 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); |
fa12a08e ZRR |
242 | |
243 | reg = phy_read(phydev, | |
76f11d3a | 244 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); |
fa12a08e ZRR |
245 | |
246 | reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); | |
247 | ||
248 | if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES) | |
249 | reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII; | |
250 | else | |
251 | reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII; | |
252 | ||
253 | phy_write(phydev, | |
76f11d3a | 254 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); |
9082eeac AF |
255 | } |
256 | ||
fa12a08e ZRR |
257 | if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { |
258 | reg = phy_read(phydev, | |
76f11d3a | 259 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); |
fa12a08e ZRR |
260 | |
261 | reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); | |
262 | reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; | |
263 | reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; | |
264 | ||
265 | phy_write(phydev, MDIO_DEVAD_NONE, | |
76f11d3a | 266 | MIIM_88E1111_PHY_EXT_SR, reg); |
fa12a08e ZRR |
267 | } |
268 | ||
269 | if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { | |
270 | reg = phy_read(phydev, | |
76f11d3a | 271 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); |
fa12a08e ZRR |
272 | reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); |
273 | phy_write(phydev, | |
76f11d3a | 274 | MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); |
fa12a08e ZRR |
275 | |
276 | reg = phy_read(phydev, MDIO_DEVAD_NONE, | |
76f11d3a | 277 | MIIM_88E1111_PHY_EXT_SR); |
fa12a08e ZRR |
278 | reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | |
279 | MIIM_88E1111_HWCFG_FIBER_COPPER_RES); | |
280 | reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; | |
281 | phy_write(phydev, MDIO_DEVAD_NONE, | |
76f11d3a | 282 | MIIM_88E1111_PHY_EXT_SR, reg); |
fa12a08e ZRR |
283 | |
284 | /* soft reset */ | |
3089c47d | 285 | phy_reset(phydev); |
fa12a08e ZRR |
286 | |
287 | reg = phy_read(phydev, MDIO_DEVAD_NONE, | |
76f11d3a | 288 | MIIM_88E1111_PHY_EXT_SR); |
fa12a08e | 289 | reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | |
76f11d3a | 290 | MIIM_88E1111_HWCFG_FIBER_COPPER_RES); |
fa12a08e ZRR |
291 | reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI | |
292 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; | |
293 | phy_write(phydev, MDIO_DEVAD_NONE, | |
76f11d3a | 294 | MIIM_88E1111_PHY_EXT_SR, reg); |
fa12a08e ZRR |
295 | } |
296 | ||
297 | /* soft reset */ | |
3089c47d | 298 | phy_reset(phydev); |
9082eeac AF |
299 | |
300 | genphy_config_aneg(phydev); | |
a8c3eca4 | 301 | genphy_restart_aneg(phydev); |
9082eeac AF |
302 | |
303 | return 0; | |
304 | } | |
305 | ||
35fa0dda HZ |
306 | /** |
307 | * m88e1518_phy_writebits - write bits to a register | |
308 | */ | |
309 | void m88e1518_phy_writebits(struct phy_device *phydev, | |
76f11d3a | 310 | u8 reg_num, u16 offset, u16 len, u16 data) |
35fa0dda HZ |
311 | { |
312 | u16 reg, mask; | |
313 | ||
314 | if ((len + offset) >= 16) | |
315 | mask = 0 - (1 << offset); | |
316 | else | |
317 | mask = (1 << (len + offset)) - (1 << offset); | |
318 | ||
319 | reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num); | |
320 | ||
321 | reg &= ~mask; | |
322 | reg |= data << offset; | |
323 | ||
324 | phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg); | |
325 | } | |
326 | ||
327 | static int m88e1518_config(struct phy_device *phydev) | |
328 | { | |
68e6ecad PE |
329 | u16 reg; |
330 | ||
35fa0dda HZ |
331 | /* |
332 | * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 | |
333 | * /88E1514 Rev A0, Errata Section 3.1 | |
334 | */ | |
90a94ef6 CG |
335 | |
336 | /* EEE initialization */ | |
93cc2959 | 337 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff); |
90a94ef6 CG |
338 | phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B); |
339 | phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144); | |
340 | phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28); | |
341 | phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146); | |
342 | phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233); | |
343 | phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D); | |
344 | phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C); | |
345 | phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159); | |
93cc2959 | 346 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); |
90a94ef6 CG |
347 | |
348 | /* SGMII-to-Copper mode initialization */ | |
35fa0dda | 349 | if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { |
90a94ef6 | 350 | /* Select page 18 */ |
93cc2959 | 351 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 18); |
90a94ef6 CG |
352 | |
353 | /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ | |
93cc2959 JH |
354 | m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL, |
355 | 0, 3, MIIM_88E151x_MODE_SGMII); | |
35fa0dda | 356 | |
90a94ef6 | 357 | /* PHY reset is necessary after changing MODE[2:0] */ |
93cc2959 JH |
358 | m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL, |
359 | MIIM_88E151x_RESET_OFFS, 1, 1); | |
90a94ef6 CG |
360 | |
361 | /* Reset page selection */ | |
93cc2959 | 362 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0); |
90a94ef6 | 363 | |
35fa0dda HZ |
364 | udelay(100); |
365 | } | |
366 | ||
68e6ecad PE |
367 | if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { |
368 | reg = phy_read(phydev, MDIO_DEVAD_NONE, | |
369 | MIIM_88E1111_PHY_EXT_SR); | |
370 | ||
371 | reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); | |
372 | reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; | |
373 | reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; | |
374 | ||
375 | phy_write(phydev, MDIO_DEVAD_NONE, | |
376 | MIIM_88E1111_PHY_EXT_SR, reg); | |
377 | } | |
378 | ||
379 | if (phy_interface_is_rgmii(phydev)) { | |
380 | phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 2); | |
381 | ||
382 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR); | |
383 | reg &= ~MIIM_88E151x_RGMII_RXTX_DELAY; | |
431be621 MS |
384 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII || |
385 | phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) | |
68e6ecad PE |
386 | reg |= MIIM_88E151x_RGMII_RXTX_DELAY; |
387 | else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) | |
388 | reg |= MIIM_88E151x_RGMII_RX_DELAY; | |
389 | else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) | |
390 | reg |= MIIM_88E151x_RGMII_TX_DELAY; | |
391 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR, reg); | |
392 | ||
393 | phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 0); | |
394 | } | |
395 | ||
396 | /* soft reset */ | |
397 | phy_reset(phydev); | |
398 | ||
399 | genphy_config_aneg(phydev); | |
400 | genphy_restart_aneg(phydev); | |
401 | ||
402 | return 0; | |
35fa0dda HZ |
403 | } |
404 | ||
8396d0ab CG |
405 | /* Marvell 88E1510 */ |
406 | static int m88e1510_config(struct phy_device *phydev) | |
407 | { | |
408 | /* Select page 3 */ | |
93cc2959 JH |
409 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, |
410 | MIIM_88E1118_PHY_LED_PAGE); | |
8396d0ab CG |
411 | |
412 | /* Enable INTn output on LED[2] */ | |
93cc2959 JH |
413 | m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_TIMER_CTRL, |
414 | MIIM_88E151x_INT_EN_OFFS, 1, 1); | |
8396d0ab CG |
415 | |
416 | /* Configure LEDs */ | |
93cc2959 JH |
417 | /* LED[0]:0011 (ACT) */ |
418 | m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_FUNC_CTRL, | |
419 | MIIM_88E151x_LED0_OFFS, MIIM_88E151x_LED_FLD_SZ, | |
420 | MIIM_88E151x_LED0_ACT); | |
421 | /* LED[1]:0110 (LINK 100/1000 Mbps) */ | |
422 | m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_FUNC_CTRL, | |
423 | MIIM_88E151x_LED1_OFFS, MIIM_88E151x_LED_FLD_SZ, | |
424 | MIIM_88E151x_LED1_100_1000_LINK); | |
8396d0ab CG |
425 | |
426 | /* Reset page selection */ | |
93cc2959 | 427 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0); |
8396d0ab CG |
428 | |
429 | return m88e1518_config(phydev); | |
430 | } | |
431 | ||
9082eeac AF |
432 | /* Marvell 88E1118 */ |
433 | static int m88e1118_config(struct phy_device *phydev) | |
434 | { | |
435 | /* Change Page Number */ | |
436 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); | |
437 | /* Delay RGMII TX and RX */ | |
438 | phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); | |
439 | /* Change Page Number */ | |
440 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); | |
441 | /* Adjust LED control */ | |
442 | phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); | |
443 | /* Change Page Number */ | |
444 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); | |
445 | ||
1b008fdb | 446 | return genphy_config_aneg(phydev); |
9082eeac AF |
447 | } |
448 | ||
449 | static int m88e1118_startup(struct phy_device *phydev) | |
450 | { | |
b733c278 MS |
451 | int ret; |
452 | ||
9082eeac AF |
453 | /* Change Page Number */ |
454 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); | |
455 | ||
b733c278 MS |
456 | ret = genphy_update_link(phydev); |
457 | if (ret) | |
458 | return ret; | |
9082eeac | 459 | |
b733c278 | 460 | return m88e1xxx_parse_status(phydev); |
9082eeac AF |
461 | } |
462 | ||
463 | /* Marvell 88E1121R */ | |
464 | static int m88e1121_config(struct phy_device *phydev) | |
465 | { | |
466 | int pg; | |
467 | ||
468 | /* Configure the PHY */ | |
469 | genphy_config_aneg(phydev); | |
470 | ||
471 | /* Switch the page to access the led register */ | |
472 | pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); | |
473 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, | |
76f11d3a | 474 | MIIM_88E1121_PHY_LED_PAGE); |
9082eeac AF |
475 | /* Configure leds */ |
476 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, | |
76f11d3a | 477 | MIIM_88E1121_PHY_LED_DEF); |
9082eeac AF |
478 | /* Restore the page pointer */ |
479 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); | |
480 | ||
481 | /* Disable IRQs and de-assert interrupt */ | |
482 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); | |
483 | phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); | |
484 | ||
485 | return 0; | |
486 | } | |
487 | ||
488 | /* Marvell 88E1145 */ | |
489 | static int m88e1145_config(struct phy_device *phydev) | |
490 | { | |
491 | int reg; | |
492 | ||
493 | /* Errata E0, E1 */ | |
494 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); | |
495 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); | |
496 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); | |
497 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); | |
498 | ||
499 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, | |
76f11d3a | 500 | MIIM_88E1xxx_PHY_MDI_X_AUTO); |
9082eeac AF |
501 | |
502 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); | |
503 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) | |
504 | reg |= MIIM_M88E1145_RGMII_RX_DELAY | | |
505 | MIIM_M88E1145_RGMII_TX_DELAY; | |
506 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); | |
507 | ||
508 | genphy_config_aneg(phydev); | |
509 | ||
ef621da7 YS |
510 | /* soft reset */ |
511 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); | |
512 | reg |= BMCR_RESET; | |
513 | phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg); | |
9082eeac AF |
514 | |
515 | return 0; | |
516 | } | |
517 | ||
518 | static int m88e1145_startup(struct phy_device *phydev) | |
519 | { | |
b733c278 MS |
520 | int ret; |
521 | ||
522 | ret = genphy_update_link(phydev); | |
523 | if (ret) | |
524 | return ret; | |
525 | ||
9082eeac | 526 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, |
76f11d3a | 527 | MIIM_88E1145_PHY_LED_DIRECT); |
b733c278 | 528 | return m88e1xxx_parse_status(phydev); |
9082eeac AF |
529 | } |
530 | ||
531 | /* Marvell 88E1149S */ | |
532 | static int m88e1149_config(struct phy_device *phydev) | |
533 | { | |
534 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); | |
535 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); | |
536 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); | |
537 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); | |
538 | phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); | |
539 | ||
540 | genphy_config_aneg(phydev); | |
541 | ||
542 | phy_reset(phydev); | |
543 | ||
544 | return 0; | |
545 | } | |
546 | ||
aeceec0d SH |
547 | /* Marvell 88E1310 */ |
548 | static int m88e1310_config(struct phy_device *phydev) | |
549 | { | |
550 | u16 reg; | |
551 | ||
552 | /* LED link and activity */ | |
553 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); | |
554 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL); | |
555 | reg = (reg & ~0xf) | 0x1; | |
556 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg); | |
557 | ||
558 | /* Set LED2/INT to INT mode, low active */ | |
559 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); | |
560 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN); | |
561 | reg = (reg & 0x77ff) | 0x0880; | |
562 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg); | |
563 | ||
564 | /* Set RGMII delay */ | |
565 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002); | |
566 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL); | |
567 | reg |= 0x0030; | |
568 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg); | |
569 | ||
570 | /* Ensure to return to page 0 */ | |
571 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); | |
572 | ||
08e64cec | 573 | return genphy_config_aneg(phydev); |
aeceec0d | 574 | } |
9082eeac | 575 | |
c52d428d DE |
576 | static int m88e1680_config(struct phy_device *phydev) |
577 | { | |
578 | /* | |
579 | * As per Marvell Release Notes - Alaska V 88E1680 Rev A2 | |
580 | * Errata Section 4.1 | |
581 | */ | |
582 | u16 reg; | |
583 | int res; | |
584 | ||
585 | /* Matrix LED mode (not neede if single LED mode is used */ | |
586 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0004); | |
587 | reg = phy_read(phydev, MDIO_DEVAD_NONE, 27); | |
588 | reg |= (1 << 5); | |
589 | phy_write(phydev, MDIO_DEVAD_NONE, 27, reg); | |
590 | ||
591 | /* QSGMII TX amplitude change */ | |
592 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00fd); | |
593 | phy_write(phydev, MDIO_DEVAD_NONE, 8, 0x0b53); | |
594 | phy_write(phydev, MDIO_DEVAD_NONE, 7, 0x200d); | |
595 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); | |
596 | ||
597 | /* EEE initialization */ | |
598 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff); | |
599 | phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb030); | |
600 | phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x215c); | |
601 | phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fc); | |
602 | phy_write(phydev, MDIO_DEVAD_NONE, 24, 0x888c); | |
603 | phy_write(phydev, MDIO_DEVAD_NONE, 25, 0x888c); | |
604 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); | |
605 | phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140); | |
606 | ||
607 | res = genphy_config_aneg(phydev); | |
608 | if (res < 0) | |
609 | return res; | |
610 | ||
611 | /* soft reset */ | |
612 | reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); | |
613 | reg |= BMCR_RESET; | |
614 | phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg); | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
9082eeac AF |
619 | static struct phy_driver M88E1011S_driver = { |
620 | .name = "Marvell 88E1011S", | |
621 | .uid = 0x1410c60, | |
622 | .mask = 0xffffff0, | |
623 | .features = PHY_GBIT_FEATURES, | |
624 | .config = &m88e1011s_config, | |
625 | .startup = &m88e1011s_startup, | |
626 | .shutdown = &genphy_shutdown, | |
627 | }; | |
628 | ||
629 | static struct phy_driver M88E1111S_driver = { | |
630 | .name = "Marvell 88E1111S", | |
631 | .uid = 0x1410cc0, | |
632 | .mask = 0xffffff0, | |
633 | .features = PHY_GBIT_FEATURES, | |
634 | .config = &m88e1111s_config, | |
635 | .startup = &m88e1011s_startup, | |
636 | .shutdown = &genphy_shutdown, | |
637 | }; | |
638 | ||
639 | static struct phy_driver M88E1118_driver = { | |
640 | .name = "Marvell 88E1118", | |
641 | .uid = 0x1410e10, | |
642 | .mask = 0xffffff0, | |
643 | .features = PHY_GBIT_FEATURES, | |
644 | .config = &m88e1118_config, | |
645 | .startup = &m88e1118_startup, | |
646 | .shutdown = &genphy_shutdown, | |
647 | }; | |
648 | ||
b4b81e83 MS |
649 | static struct phy_driver M88E1118R_driver = { |
650 | .name = "Marvell 88E1118R", | |
651 | .uid = 0x1410e40, | |
652 | .mask = 0xffffff0, | |
653 | .features = PHY_GBIT_FEATURES, | |
654 | .config = &m88e1118_config, | |
655 | .startup = &m88e1118_startup, | |
656 | .shutdown = &genphy_shutdown, | |
657 | }; | |
658 | ||
9082eeac AF |
659 | static struct phy_driver M88E1121R_driver = { |
660 | .name = "Marvell 88E1121R", | |
661 | .uid = 0x1410cb0, | |
662 | .mask = 0xffffff0, | |
663 | .features = PHY_GBIT_FEATURES, | |
664 | .config = &m88e1121_config, | |
665 | .startup = &genphy_startup, | |
666 | .shutdown = &genphy_shutdown, | |
667 | }; | |
668 | ||
669 | static struct phy_driver M88E1145_driver = { | |
670 | .name = "Marvell 88E1145", | |
671 | .uid = 0x1410cd0, | |
672 | .mask = 0xffffff0, | |
673 | .features = PHY_GBIT_FEATURES, | |
674 | .config = &m88e1145_config, | |
675 | .startup = &m88e1145_startup, | |
676 | .shutdown = &genphy_shutdown, | |
677 | }; | |
678 | ||
679 | static struct phy_driver M88E1149S_driver = { | |
680 | .name = "Marvell 88E1149S", | |
681 | .uid = 0x1410ca0, | |
682 | .mask = 0xffffff0, | |
683 | .features = PHY_GBIT_FEATURES, | |
684 | .config = &m88e1149_config, | |
685 | .startup = &m88e1011s_startup, | |
686 | .shutdown = &genphy_shutdown, | |
687 | }; | |
688 | ||
8396d0ab CG |
689 | static struct phy_driver M88E1510_driver = { |
690 | .name = "Marvell 88E1510", | |
691 | .uid = 0x1410dd0, | |
83cfbeb0 | 692 | .mask = 0xfffffff, |
8396d0ab CG |
693 | .features = PHY_GBIT_FEATURES, |
694 | .config = &m88e1510_config, | |
695 | .startup = &m88e1011s_startup, | |
696 | .shutdown = &genphy_shutdown, | |
ce27eb9b LM |
697 | .readext = &m88e1xxx_phy_extread, |
698 | .writeext = &m88e1xxx_phy_extwrite, | |
8396d0ab CG |
699 | }; |
700 | ||
998640b4 PE |
701 | /* |
702 | * This supports: | |
703 | * 88E1518, uid 0x1410dd1 | |
704 | * 88E1512, uid 0x1410dd4 | |
705 | */ | |
1415107e MS |
706 | static struct phy_driver M88E1518_driver = { |
707 | .name = "Marvell 88E1518", | |
998640b4 PE |
708 | .uid = 0x1410dd0, |
709 | .mask = 0xffffffa, | |
1415107e | 710 | .features = PHY_GBIT_FEATURES, |
35fa0dda | 711 | .config = &m88e1518_config, |
1415107e MS |
712 | .startup = &m88e1011s_startup, |
713 | .shutdown = &genphy_shutdown, | |
ce27eb9b LM |
714 | .readext = &m88e1xxx_phy_extread, |
715 | .writeext = &m88e1xxx_phy_extwrite, | |
1415107e MS |
716 | }; |
717 | ||
aeceec0d SH |
718 | static struct phy_driver M88E1310_driver = { |
719 | .name = "Marvell 88E1310", | |
720 | .uid = 0x01410e90, | |
721 | .mask = 0xffffff0, | |
722 | .features = PHY_GBIT_FEATURES, | |
723 | .config = &m88e1310_config, | |
724 | .startup = &m88e1011s_startup, | |
725 | .shutdown = &genphy_shutdown, | |
726 | }; | |
727 | ||
c52d428d DE |
728 | static struct phy_driver M88E1680_driver = { |
729 | .name = "Marvell 88E1680", | |
730 | .uid = 0x1410ed0, | |
731 | .mask = 0xffffff0, | |
732 | .features = PHY_GBIT_FEATURES, | |
733 | .config = &m88e1680_config, | |
734 | .startup = &genphy_startup, | |
735 | .shutdown = &genphy_shutdown, | |
736 | }; | |
737 | ||
9082eeac AF |
738 | int phy_marvell_init(void) |
739 | { | |
aeceec0d | 740 | phy_register(&M88E1310_driver); |
9082eeac AF |
741 | phy_register(&M88E1149S_driver); |
742 | phy_register(&M88E1145_driver); | |
743 | phy_register(&M88E1121R_driver); | |
744 | phy_register(&M88E1118_driver); | |
b4b81e83 | 745 | phy_register(&M88E1118R_driver); |
9082eeac AF |
746 | phy_register(&M88E1111S_driver); |
747 | phy_register(&M88E1011S_driver); | |
8396d0ab | 748 | phy_register(&M88E1510_driver); |
1415107e | 749 | phy_register(&M88E1518_driver); |
c52d428d | 750 | phy_register(&M88E1680_driver); |
9082eeac AF |
751 | |
752 | return 0; | |
753 | } |