blob: 1dcb79db242907f59614c05242cc28d002088355 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Andy Fleming60ca78b2011-04-07 21:56:05 -05002/*
3 * Marvell PHY drivers
4 *
Andy Fleming60ca78b2011-04-07 21:56:05 -05005 * Copyright 2010-2011 Freescale Semiconductor, Inc.
6 * author Andy Fleming
Andy Fleming60ca78b2011-04-07 21:56:05 -05007 */
Andy Fleming60ca78b2011-04-07 21:56:05 -05008#include <common.h>
Simon Glassb3d61dd2016-07-05 17:10:12 -06009#include <errno.h>
Andy Fleming60ca78b2011-04-07 21:56:05 -050010#include <phy.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060011#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060012#include <linux/delay.h>
Andy Fleming60ca78b2011-04-07 21:56:05 -050013
14#define PHY_AUTONEGOTIATE_TIMEOUT 5000
15
Phil Edworthy19d03be2017-05-24 14:43:06 +010016#define MII_MARVELL_PHY_PAGE 22
17
Andy Fleming60ca78b2011-04-07 21:56:05 -050018/* 88E1011 PHY Status Register */
19#define MIIM_88E1xxx_PHY_STATUS 0x11
20#define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000
21#define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000
22#define MIIM_88E1xxx_PHYSTAT_100 0x4000
23#define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000
24#define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800
25#define MIIM_88E1xxx_PHYSTAT_LINK 0x0400
26
27#define MIIM_88E1xxx_PHY_SCR 0x10
28#define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060
29
30/* 88E1111 PHY LED Control Register */
31#define MIIM_88E1111_PHY_LED_CONTROL 24
32#define MIIM_88E1111_PHY_LED_DIRECT 0x4100
33#define MIIM_88E1111_PHY_LED_COMBINE 0x411C
34
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +000035/* 88E1111 Extended PHY Specific Control Register */
36#define MIIM_88E1111_PHY_EXT_CR 0x14
37#define MIIM_88E1111_RX_DELAY 0x80
38#define MIIM_88E1111_TX_DELAY 0x2
39
40/* 88E1111 Extended PHY Specific Status Register */
41#define MIIM_88E1111_PHY_EXT_SR 0x1b
42#define MIIM_88E1111_HWCFG_MODE_MASK 0xf
43#define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb
44#define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3
45#define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4
46#define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9
47#define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000
48#define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000
49
50#define MIIM_88E1111_COPPER 0
51#define MIIM_88E1111_FIBER 1
52
Andy Fleming60ca78b2011-04-07 21:56:05 -050053/* 88E1118 PHY defines */
54#define MIIM_88E1118_PHY_PAGE 22
55#define MIIM_88E1118_PHY_LED_PAGE 3
56
57/* 88E1121 PHY LED Control Register */
58#define MIIM_88E1121_PHY_LED_CTRL 16
59#define MIIM_88E1121_PHY_LED_PAGE 3
60#define MIIM_88E1121_PHY_LED_DEF 0x0030
61
62/* 88E1121 PHY IRQ Enable/Status Register */
63#define MIIM_88E1121_PHY_IRQ_EN 18
64#define MIIM_88E1121_PHY_IRQ_STATUS 19
65
66#define MIIM_88E1121_PHY_PAGE 22
67
68/* 88E1145 Extended PHY Specific Control Register */
69#define MIIM_88E1145_PHY_EXT_CR 20
70#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080
71#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002
72
73#define MIIM_88E1145_PHY_LED_CONTROL 24
74#define MIIM_88E1145_PHY_LED_DIRECT 0x4100
75
76#define MIIM_88E1145_PHY_PAGE 29
77#define MIIM_88E1145_PHY_CAL_OV 30
78
79#define MIIM_88E1149_PHY_PAGE 29
80
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +010081/* 88E1310 PHY defines */
82#define MIIM_88E1310_PHY_LED_CTRL 16
83#define MIIM_88E1310_PHY_IRQ_EN 18
84#define MIIM_88E1310_PHY_RGMII_CTRL 21
85#define MIIM_88E1310_PHY_PAGE 22
86
Joe Hershberger27a8e032016-12-09 11:54:39 -060087/* 88E151x PHY defines */
Phil Edworthy19d03be2017-05-24 14:43:06 +010088/* Page 2 registers */
89#define MIIM_88E151x_PHY_MSCR 21
90#define MIIM_88E151x_RGMII_RX_DELAY BIT(5)
91#define MIIM_88E151x_RGMII_TX_DELAY BIT(4)
92#define MIIM_88E151x_RGMII_RXTX_DELAY (BIT(5) | BIT(4))
Joe Hershberger27a8e032016-12-09 11:54:39 -060093/* Page 3 registers */
94#define MIIM_88E151x_LED_FUNC_CTRL 16
95#define MIIM_88E151x_LED_FLD_SZ 4
96#define MIIM_88E151x_LED0_OFFS (0 * MIIM_88E151x_LED_FLD_SZ)
97#define MIIM_88E151x_LED1_OFFS (1 * MIIM_88E151x_LED_FLD_SZ)
98#define MIIM_88E151x_LED0_ACT 3
99#define MIIM_88E151x_LED1_100_1000_LINK 6
100#define MIIM_88E151x_LED_TIMER_CTRL 18
101#define MIIM_88E151x_INT_EN_OFFS 7
102/* Page 18 registers */
103#define MIIM_88E151x_GENERAL_CTRL 20
104#define MIIM_88E151x_MODE_SGMII 1
105#define MIIM_88E151x_RESET_OFFS 15
106
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200107#if IS_ENABLED(CONFIG_DM_ETH)
108static int marvell_read_page(struct phy_device *phydev)
109{
110 return phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
111}
112
113static int marvell_write_page(struct phy_device *phydev, int page)
114{
115 return phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, page);
116}
117
118/* Set and/or override some configuration registers based on the
119 * marvell,reg-init property stored in the of_node for the phydev.
120 *
121 * marvell,reg-init = <reg-page reg mask value>,...;
122 *
123 * There may be one or more sets of <reg-page reg mask value>:
124 *
125 * reg-page: which register bank to use.
126 * reg: the register.
127 * mask: if non-zero, ANDed with existing register value.
128 * value: ORed with the masked value and written to the regiser.
129 *
130 */
131static int marvell_of_reg_init(struct phy_device *phydev)
132{
133 const __be32 *prop;
134 int len, i, saved_page, current_page, ret = 0;
135
136 if (!ofnode_valid(phydev->node))
137 return 0;
138
139 prop = ofnode_get_property(phydev->node, "marvell,reg-init", &len);
140 if (!prop)
141 return 0;
142
143 saved_page = marvell_read_page(phydev);
144 if (saved_page < 0)
145 goto err;
146 current_page = saved_page;
147
148 len /= sizeof(*prop);
149 for (i = 0; i < len - 3; i += 4) {
150 u16 page = be32_to_cpup(prop + i);
151 u16 reg = be32_to_cpup(prop + i + 1);
152 u16 mask = be32_to_cpup(prop + i + 2);
153 u16 val_bits = be32_to_cpup(prop + i + 3);
154 int val;
155
156 if (page != current_page) {
157 current_page = page;
158 ret = marvell_write_page(phydev, page);
159 if (ret < 0)
160 goto err;
161 }
162
163 val = 0;
164 if (mask) {
165 val = phy_read(phydev, MDIO_DEVAD_NONE, reg);
166 if (val < 0) {
167 ret = val;
168 goto err;
169 }
170 val &= mask;
171 }
172 val |= val_bits;
173
174 ret = phy_write(phydev, MDIO_DEVAD_NONE, reg, val);
175 if (ret < 0)
176 goto err;
177 }
178
179err:
180 return marvell_write_page(phydev, saved_page);
181}
182#else
183static int marvell_of_reg_init(struct phy_device *phydev)
184{
185 return 0;
186}
187#endif /* CONFIG_DM_ETH */
188
Lukasz Majewski3857a162017-10-30 22:57:53 +0100189static int m88e1xxx_phy_extread(struct phy_device *phydev, int addr,
190 int devaddr, int regnum)
191{
192 int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
193 int val;
194
195 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr);
196 val = phy_read(phydev, MDIO_DEVAD_NONE, regnum);
197 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage);
198
199 return val;
200}
201
202static int m88e1xxx_phy_extwrite(struct phy_device *phydev, int addr,
203 int devaddr, int regnum, u16 val)
204{
205 int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
206
207 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr);
208 phy_write(phydev, MDIO_DEVAD_NONE, regnum, val);
209 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage);
210
211 return 0;
212}
213
Andy Fleming60ca78b2011-04-07 21:56:05 -0500214/* Marvell 88E1011S */
215static int m88e1011s_config(struct phy_device *phydev)
216{
217 /* Reset and configure the PHY */
218 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
219
220 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
221 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
222 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5);
223 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0);
224 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
225
226 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
227
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200228 marvell_of_reg_init(phydev);
229
Andy Fleming60ca78b2011-04-07 21:56:05 -0500230 genphy_config_aneg(phydev);
231
232 return 0;
233}
234
235/* Parse the 88E1011's status register for speed and duplex
236 * information
237 */
Michal Simekcf6677b2016-05-18 12:48:57 +0200238static int m88e1xxx_parse_status(struct phy_device *phydev)
Andy Fleming60ca78b2011-04-07 21:56:05 -0500239{
240 unsigned int speed;
241 unsigned int mii_reg;
242
243 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS);
244
245 if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) &&
Mario Six618d42b2018-01-15 11:08:24 +0100246 !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500247 int i = 0;
248
249 puts("Waiting for PHY realtime link");
250 while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
251 /* Timeout reached ? */
252 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
253 puts(" TIMEOUT !\n");
254 phydev->link = 0;
Michal Simekcf6677b2016-05-18 12:48:57 +0200255 return -ETIMEDOUT;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500256 }
257
258 if ((i++ % 1000) == 0)
259 putc('.');
260 udelay(1000);
261 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100262 MIIM_88E1xxx_PHY_STATUS);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500263 }
264 puts(" done\n");
Mario Six618d42b2018-01-15 11:08:24 +0100265 mdelay(500); /* another 500 ms (results in faster booting) */
Andy Fleming60ca78b2011-04-07 21:56:05 -0500266 } else {
267 if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK)
268 phydev->link = 1;
269 else
270 phydev->link = 0;
271 }
272
273 if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX)
274 phydev->duplex = DUPLEX_FULL;
275 else
276 phydev->duplex = DUPLEX_HALF;
277
278 speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED;
279
280 switch (speed) {
281 case MIIM_88E1xxx_PHYSTAT_GBIT:
282 phydev->speed = SPEED_1000;
283 break;
284 case MIIM_88E1xxx_PHYSTAT_100:
285 phydev->speed = SPEED_100;
286 break;
287 default:
288 phydev->speed = SPEED_10;
289 break;
290 }
291
292 return 0;
293}
294
295static int m88e1011s_startup(struct phy_device *phydev)
296{
Michal Simek5ff89662016-05-18 12:46:12 +0200297 int ret;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500298
Michal Simek5ff89662016-05-18 12:46:12 +0200299 ret = genphy_update_link(phydev);
300 if (ret)
301 return ret;
302
303 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500304}
305
306/* Marvell 88E1111S */
307static int m88e1111s_config(struct phy_device *phydev)
308{
309 int reg;
310
Phil Edworthye4c26ee2016-12-12 12:54:15 +0000311 if (phy_interface_is_rgmii(phydev)) {
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000312 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100313 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000314 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
Mario Six618d42b2018-01-15 11:08:24 +0100315 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) {
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000316 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
317 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
318 reg &= ~MIIM_88E1111_TX_DELAY;
319 reg |= MIIM_88E1111_RX_DELAY;
320 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
321 reg &= ~MIIM_88E1111_RX_DELAY;
322 reg |= MIIM_88E1111_TX_DELAY;
323 }
324
325 phy_write(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100326 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000327
328 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100329 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000330
331 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
332
333 if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES)
334 reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII;
335 else
336 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII;
337
338 phy_write(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100339 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000340 }
341
342 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
343 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100344 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000345
346 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
347 reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
348 reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
349
350 phy_write(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100351 MIIM_88E1111_PHY_EXT_SR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000352 }
353
354 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
355 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100356 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000357 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
358 phy_write(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100359 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000360
361 reg = phy_read(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100362 MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000363 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
364 MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
365 reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
366 phy_write(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100367 MIIM_88E1111_PHY_EXT_SR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000368
369 /* soft reset */
Stefan Roesed1b52822016-02-10 07:06:05 +0100370 phy_reset(phydev);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000371
372 reg = phy_read(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100373 MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000374 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
Mario Six618d42b2018-01-15 11:08:24 +0100375 MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000376 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI |
377 MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
378 phy_write(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100379 MIIM_88E1111_PHY_EXT_SR, reg);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500380 }
381
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000382 /* soft reset */
Stefan Roesed1b52822016-02-10 07:06:05 +0100383 phy_reset(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500384
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200385 marvell_of_reg_init(phydev);
386
Andy Fleming60ca78b2011-04-07 21:56:05 -0500387 genphy_config_aneg(phydev);
Stefan Roeseeb06f022016-02-10 07:06:06 +0100388 genphy_restart_aneg(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500389
390 return 0;
391}
392
Hao Zhangf0c53a42014-10-30 18:59:43 +0200393/**
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100394 * m88e151x_phy_writebits - write bits to a register
Hao Zhangf0c53a42014-10-30 18:59:43 +0200395 */
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100396void m88e151x_phy_writebits(struct phy_device *phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100397 u8 reg_num, u16 offset, u16 len, u16 data)
Hao Zhangf0c53a42014-10-30 18:59:43 +0200398{
399 u16 reg, mask;
400
401 if ((len + offset) >= 16)
402 mask = 0 - (1 << offset);
403 else
404 mask = (1 << (len + offset)) - (1 << offset);
405
406 reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num);
407
408 reg &= ~mask;
409 reg |= data << offset;
410
411 phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
412}
413
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100414static int m88e151x_config(struct phy_device *phydev)
Hao Zhangf0c53a42014-10-30 18:59:43 +0200415{
Phil Edworthy19d03be2017-05-24 14:43:06 +0100416 u16 reg;
417
Hao Zhangf0c53a42014-10-30 18:59:43 +0200418 /*
419 * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512
420 * /88E1514 Rev A0, Errata Section 3.1
421 */
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200422
423 /* EEE initialization */
Joe Hershberger27a8e032016-12-09 11:54:39 -0600424 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200425 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B);
426 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
427 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28);
428 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
429 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233);
430 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D);
431 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C);
432 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
Joe Hershberger27a8e032016-12-09 11:54:39 -0600433 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200434
435 /* SGMII-to-Copper mode initialization */
Hao Zhangf0c53a42014-10-30 18:59:43 +0200436 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200437 /* Select page 18 */
Joe Hershberger27a8e032016-12-09 11:54:39 -0600438 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 18);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200439
440 /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100441 m88e151x_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
Joe Hershberger27a8e032016-12-09 11:54:39 -0600442 0, 3, MIIM_88E151x_MODE_SGMII);
Hao Zhangf0c53a42014-10-30 18:59:43 +0200443
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200444 /* PHY reset is necessary after changing MODE[2:0] */
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100445 m88e151x_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
Joe Hershberger27a8e032016-12-09 11:54:39 -0600446 MIIM_88E151x_RESET_OFFS, 1, 1);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200447
448 /* Reset page selection */
Joe Hershberger27a8e032016-12-09 11:54:39 -0600449 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200450
Hao Zhangf0c53a42014-10-30 18:59:43 +0200451 udelay(100);
452 }
453
Phil Edworthy19d03be2017-05-24 14:43:06 +0100454 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
455 reg = phy_read(phydev, MDIO_DEVAD_NONE,
456 MIIM_88E1111_PHY_EXT_SR);
457
458 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
459 reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
460 reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
461
462 phy_write(phydev, MDIO_DEVAD_NONE,
463 MIIM_88E1111_PHY_EXT_SR, reg);
464 }
465
466 if (phy_interface_is_rgmii(phydev)) {
467 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 2);
468
469 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR);
470 reg &= ~MIIM_88E151x_RGMII_RXTX_DELAY;
Mario Sixc1de1312018-01-15 11:08:25 +0100471 if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
472 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Phil Edworthy19d03be2017-05-24 14:43:06 +0100473 reg |= MIIM_88E151x_RGMII_RXTX_DELAY;
474 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
475 reg |= MIIM_88E151x_RGMII_RX_DELAY;
476 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
477 reg |= MIIM_88E151x_RGMII_TX_DELAY;
478 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR, reg);
479
480 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 0);
481 }
482
483 /* soft reset */
484 phy_reset(phydev);
485
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200486 marvell_of_reg_init(phydev);
487
Phil Edworthy19d03be2017-05-24 14:43:06 +0100488 genphy_config_aneg(phydev);
489 genphy_restart_aneg(phydev);
490
491 return 0;
Hao Zhangf0c53a42014-10-30 18:59:43 +0200492}
493
Andy Fleming60ca78b2011-04-07 21:56:05 -0500494/* Marvell 88E1118 */
495static int m88e1118_config(struct phy_device *phydev)
496{
497 /* Change Page Number */
498 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002);
499 /* Delay RGMII TX and RX */
500 phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070);
501 /* Change Page Number */
502 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003);
503 /* Adjust LED control */
504 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e);
505 /* Change Page Number */
506 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
507
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200508 marvell_of_reg_init(phydev);
509
Michal Simek0b567102016-05-18 14:46:28 +0200510 return genphy_config_aneg(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500511}
512
513static int m88e1118_startup(struct phy_device *phydev)
514{
Michal Simek5ff89662016-05-18 12:46:12 +0200515 int ret;
516
Andy Fleming60ca78b2011-04-07 21:56:05 -0500517 /* Change Page Number */
518 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
519
Michal Simek5ff89662016-05-18 12:46:12 +0200520 ret = genphy_update_link(phydev);
521 if (ret)
522 return ret;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500523
Michal Simek5ff89662016-05-18 12:46:12 +0200524 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500525}
526
527/* Marvell 88E1121R */
528static int m88e1121_config(struct phy_device *phydev)
529{
530 int pg;
531
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200532 marvell_of_reg_init(phydev);
533
Andy Fleming60ca78b2011-04-07 21:56:05 -0500534 /* Configure the PHY */
535 genphy_config_aneg(phydev);
536
537 /* Switch the page to access the led register */
538 pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE);
539 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE,
Mario Six618d42b2018-01-15 11:08:24 +0100540 MIIM_88E1121_PHY_LED_PAGE);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500541 /* Configure leds */
542 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL,
Mario Six618d42b2018-01-15 11:08:24 +0100543 MIIM_88E1121_PHY_LED_DEF);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500544 /* Restore the page pointer */
545 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg);
546
547 /* Disable IRQs and de-assert interrupt */
548 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0);
549 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS);
550
551 return 0;
552}
553
554/* Marvell 88E1145 */
555static int m88e1145_config(struct phy_device *phydev)
556{
557 int reg;
558
559 /* Errata E0, E1 */
560 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b);
561 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f);
562 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016);
563 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da);
564
565 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR,
Mario Six618d42b2018-01-15 11:08:24 +0100566 MIIM_88E1xxx_PHY_MDI_X_AUTO);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500567
568 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR);
569 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
570 reg |= MIIM_M88E1145_RGMII_RX_DELAY |
571 MIIM_M88E1145_RGMII_TX_DELAY;
572 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg);
573
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200574 marvell_of_reg_init(phydev);
575
Andy Fleming60ca78b2011-04-07 21:56:05 -0500576 genphy_config_aneg(phydev);
577
York Sunbf94cfb2017-06-06 09:22:40 -0700578 /* soft reset */
579 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
580 reg |= BMCR_RESET;
581 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500582
583 return 0;
584}
585
586static int m88e1145_startup(struct phy_device *phydev)
587{
Michal Simek5ff89662016-05-18 12:46:12 +0200588 int ret;
589
590 ret = genphy_update_link(phydev);
591 if (ret)
592 return ret;
593
Andy Fleming60ca78b2011-04-07 21:56:05 -0500594 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
Mario Six618d42b2018-01-15 11:08:24 +0100595 MIIM_88E1145_PHY_LED_DIRECT);
Michal Simek5ff89662016-05-18 12:46:12 +0200596 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500597}
598
599/* Marvell 88E1149S */
600static int m88e1149_config(struct phy_device *phydev)
601{
602 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f);
603 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
604 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5);
605 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0);
606 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
607
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200608 marvell_of_reg_init(phydev);
609
Andy Fleming60ca78b2011-04-07 21:56:05 -0500610 genphy_config_aneg(phydev);
611
612 phy_reset(phydev);
613
614 return 0;
615}
616
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100617/* Marvell 88E1310 */
618static int m88e1310_config(struct phy_device *phydev)
619{
620 u16 reg;
621
622 /* LED link and activity */
623 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
624 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
625 reg = (reg & ~0xf) | 0x1;
626 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
627
628 /* Set LED2/INT to INT mode, low active */
629 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
630 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
631 reg = (reg & 0x77ff) | 0x0880;
632 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
633
634 /* Set RGMII delay */
635 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
636 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
637 reg |= 0x0030;
638 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
639
640 /* Ensure to return to page 0 */
641 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
642
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200643 marvell_of_reg_init(phydev);
644
Nathan Rossifcdcc552016-06-03 23:16:17 +1000645 return genphy_config_aneg(phydev);
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100646}
Andy Fleming60ca78b2011-04-07 21:56:05 -0500647
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100648static int m88e1680_config(struct phy_device *phydev)
649{
650 /*
651 * As per Marvell Release Notes - Alaska V 88E1680 Rev A2
652 * Errata Section 4.1
653 */
654 u16 reg;
655 int res;
656
657 /* Matrix LED mode (not neede if single LED mode is used */
658 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0004);
659 reg = phy_read(phydev, MDIO_DEVAD_NONE, 27);
660 reg |= (1 << 5);
661 phy_write(phydev, MDIO_DEVAD_NONE, 27, reg);
662
663 /* QSGMII TX amplitude change */
664 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00fd);
665 phy_write(phydev, MDIO_DEVAD_NONE, 8, 0x0b53);
666 phy_write(phydev, MDIO_DEVAD_NONE, 7, 0x200d);
667 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
668
669 /* EEE initialization */
670 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff);
671 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb030);
672 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x215c);
673 phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fc);
674 phy_write(phydev, MDIO_DEVAD_NONE, 24, 0x888c);
675 phy_write(phydev, MDIO_DEVAD_NONE, 25, 0x888c);
676 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
677 phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140);
678
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200679 marvell_of_reg_init(phydev);
680
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100681 res = genphy_config_aneg(phydev);
682 if (res < 0)
683 return res;
684
685 /* soft reset */
686 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
687 reg |= BMCR_RESET;
688 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
689
690 return 0;
691}
692
Andy Fleming60ca78b2011-04-07 21:56:05 -0500693static struct phy_driver M88E1011S_driver = {
694 .name = "Marvell 88E1011S",
695 .uid = 0x1410c60,
696 .mask = 0xffffff0,
697 .features = PHY_GBIT_FEATURES,
698 .config = &m88e1011s_config,
699 .startup = &m88e1011s_startup,
700 .shutdown = &genphy_shutdown,
701};
702
703static struct phy_driver M88E1111S_driver = {
704 .name = "Marvell 88E1111S",
705 .uid = 0x1410cc0,
706 .mask = 0xffffff0,
707 .features = PHY_GBIT_FEATURES,
708 .config = &m88e1111s_config,
709 .startup = &m88e1011s_startup,
710 .shutdown = &genphy_shutdown,
711};
712
713static struct phy_driver M88E1118_driver = {
714 .name = "Marvell 88E1118",
715 .uid = 0x1410e10,
716 .mask = 0xffffff0,
717 .features = PHY_GBIT_FEATURES,
718 .config = &m88e1118_config,
719 .startup = &m88e1118_startup,
720 .shutdown = &genphy_shutdown,
721};
722
Michal Simek130aa522012-08-07 02:23:07 +0000723static struct phy_driver M88E1118R_driver = {
724 .name = "Marvell 88E1118R",
725 .uid = 0x1410e40,
726 .mask = 0xffffff0,
727 .features = PHY_GBIT_FEATURES,
728 .config = &m88e1118_config,
729 .startup = &m88e1118_startup,
730 .shutdown = &genphy_shutdown,
731};
732
Andy Fleming60ca78b2011-04-07 21:56:05 -0500733static struct phy_driver M88E1121R_driver = {
734 .name = "Marvell 88E1121R",
735 .uid = 0x1410cb0,
736 .mask = 0xffffff0,
737 .features = PHY_GBIT_FEATURES,
738 .config = &m88e1121_config,
739 .startup = &genphy_startup,
740 .shutdown = &genphy_shutdown,
741};
742
743static struct phy_driver M88E1145_driver = {
744 .name = "Marvell 88E1145",
745 .uid = 0x1410cd0,
746 .mask = 0xffffff0,
747 .features = PHY_GBIT_FEATURES,
748 .config = &m88e1145_config,
749 .startup = &m88e1145_startup,
750 .shutdown = &genphy_shutdown,
751};
752
753static struct phy_driver M88E1149S_driver = {
754 .name = "Marvell 88E1149S",
755 .uid = 0x1410ca0,
756 .mask = 0xffffff0,
757 .features = PHY_GBIT_FEATURES,
758 .config = &m88e1149_config,
759 .startup = &m88e1011s_startup,
760 .shutdown = &genphy_shutdown,
761};
762
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100763static struct phy_driver M88E151x_driver = {
764 .name = "Marvell 88E151x",
Clemens Gruber89be6512015-06-06 14:44:58 +0200765 .uid = 0x1410dd0,
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100766 .mask = 0xffffff0,
Michal Simek4d74cf12012-10-15 14:03:00 +0200767 .features = PHY_GBIT_FEATURES,
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100768 .config = &m88e151x_config,
Michal Simek4d74cf12012-10-15 14:03:00 +0200769 .startup = &m88e1011s_startup,
770 .shutdown = &genphy_shutdown,
Lukasz Majewski3857a162017-10-30 22:57:53 +0100771 .readext = &m88e1xxx_phy_extread,
772 .writeext = &m88e1xxx_phy_extwrite,
Michal Simek4d74cf12012-10-15 14:03:00 +0200773};
774
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100775static struct phy_driver M88E1310_driver = {
776 .name = "Marvell 88E1310",
777 .uid = 0x01410e90,
778 .mask = 0xffffff0,
779 .features = PHY_GBIT_FEATURES,
780 .config = &m88e1310_config,
781 .startup = &m88e1011s_startup,
782 .shutdown = &genphy_shutdown,
783};
784
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100785static struct phy_driver M88E1680_driver = {
786 .name = "Marvell 88E1680",
787 .uid = 0x1410ed0,
788 .mask = 0xffffff0,
789 .features = PHY_GBIT_FEATURES,
790 .config = &m88e1680_config,
791 .startup = &genphy_startup,
792 .shutdown = &genphy_shutdown,
793};
794
Andy Fleming60ca78b2011-04-07 21:56:05 -0500795int phy_marvell_init(void)
796{
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100797 phy_register(&M88E1310_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500798 phy_register(&M88E1149S_driver);
799 phy_register(&M88E1145_driver);
800 phy_register(&M88E1121R_driver);
801 phy_register(&M88E1118_driver);
Michal Simek130aa522012-08-07 02:23:07 +0000802 phy_register(&M88E1118R_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500803 phy_register(&M88E1111S_driver);
804 phy_register(&M88E1011S_driver);
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100805 phy_register(&M88E151x_driver);
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100806 phy_register(&M88E1680_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500807
808 return 0;
809}