blob: 08608a99b9d06d5d4cbde5d87a4de7721f06fe3f [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 */
Simon Glassb3d61dd2016-07-05 17:10:12 -06008#include <errno.h>
Marek Vasutf7c5c232023-03-19 18:08:06 +01009#include <marvell_phy.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 +0200107static int marvell_read_page(struct phy_device *phydev)
108{
109 return phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
110}
111
112static int marvell_write_page(struct phy_device *phydev, int page)
113{
114 return phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, page);
115}
116
117/* Set and/or override some configuration registers based on the
118 * marvell,reg-init property stored in the of_node for the phydev.
119 *
120 * marvell,reg-init = <reg-page reg mask value>,...;
121 *
122 * There may be one or more sets of <reg-page reg mask value>:
123 *
124 * reg-page: which register bank to use.
125 * reg: the register.
126 * mask: if non-zero, ANDed with existing register value.
127 * value: ORed with the masked value and written to the regiser.
128 *
129 */
130static int marvell_of_reg_init(struct phy_device *phydev)
131{
132 const __be32 *prop;
133 int len, i, saved_page, current_page, ret = 0;
134
135 if (!ofnode_valid(phydev->node))
136 return 0;
137
138 prop = ofnode_get_property(phydev->node, "marvell,reg-init", &len);
139 if (!prop)
140 return 0;
141
142 saved_page = marvell_read_page(phydev);
143 if (saved_page < 0)
144 goto err;
145 current_page = saved_page;
146
147 len /= sizeof(*prop);
148 for (i = 0; i < len - 3; i += 4) {
149 u16 page = be32_to_cpup(prop + i);
150 u16 reg = be32_to_cpup(prop + i + 1);
151 u16 mask = be32_to_cpup(prop + i + 2);
152 u16 val_bits = be32_to_cpup(prop + i + 3);
153 int val;
154
155 if (page != current_page) {
156 current_page = page;
157 ret = marvell_write_page(phydev, page);
158 if (ret < 0)
159 goto err;
160 }
161
162 val = 0;
163 if (mask) {
164 val = phy_read(phydev, MDIO_DEVAD_NONE, reg);
165 if (val < 0) {
166 ret = val;
167 goto err;
168 }
169 val &= mask;
170 }
171 val |= val_bits;
172
173 ret = phy_write(phydev, MDIO_DEVAD_NONE, reg, val);
174 if (ret < 0)
175 goto err;
176 }
177
178err:
179 return marvell_write_page(phydev, saved_page);
180}
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200181
Lukasz Majewski3857a162017-10-30 22:57:53 +0100182static int m88e1xxx_phy_extread(struct phy_device *phydev, int addr,
183 int devaddr, int regnum)
184{
185 int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
186 int val;
187
188 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr);
189 val = phy_read(phydev, MDIO_DEVAD_NONE, regnum);
190 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage);
191
192 return val;
193}
194
195static int m88e1xxx_phy_extwrite(struct phy_device *phydev, int addr,
196 int devaddr, int regnum, u16 val)
197{
198 int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
199
200 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr);
201 phy_write(phydev, MDIO_DEVAD_NONE, regnum, val);
202 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage);
203
204 return 0;
205}
206
Andy Fleming60ca78b2011-04-07 21:56:05 -0500207/* Marvell 88E1011S */
208static int m88e1011s_config(struct phy_device *phydev)
209{
210 /* Reset and configure the PHY */
211 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
212
213 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
214 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
215 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5);
216 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0);
217 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
218
219 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
220
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200221 marvell_of_reg_init(phydev);
222
Andy Fleming60ca78b2011-04-07 21:56:05 -0500223 genphy_config_aneg(phydev);
224
225 return 0;
226}
227
228/* Parse the 88E1011's status register for speed and duplex
229 * information
230 */
Michal Simekcf6677b2016-05-18 12:48:57 +0200231static int m88e1xxx_parse_status(struct phy_device *phydev)
Andy Fleming60ca78b2011-04-07 21:56:05 -0500232{
233 unsigned int speed;
234 unsigned int mii_reg;
235
236 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS);
237
238 if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) &&
Mario Six618d42b2018-01-15 11:08:24 +0100239 !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500240 int i = 0;
241
242 puts("Waiting for PHY realtime link");
243 while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
244 /* Timeout reached ? */
245 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
246 puts(" TIMEOUT !\n");
247 phydev->link = 0;
Michal Simekcf6677b2016-05-18 12:48:57 +0200248 return -ETIMEDOUT;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500249 }
250
251 if ((i++ % 1000) == 0)
252 putc('.');
253 udelay(1000);
254 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100255 MIIM_88E1xxx_PHY_STATUS);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500256 }
257 puts(" done\n");
Mario Six618d42b2018-01-15 11:08:24 +0100258 mdelay(500); /* another 500 ms (results in faster booting) */
Andy Fleming60ca78b2011-04-07 21:56:05 -0500259 } else {
260 if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK)
261 phydev->link = 1;
262 else
263 phydev->link = 0;
264 }
265
266 if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX)
267 phydev->duplex = DUPLEX_FULL;
268 else
269 phydev->duplex = DUPLEX_HALF;
270
271 speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED;
272
273 switch (speed) {
274 case MIIM_88E1xxx_PHYSTAT_GBIT:
275 phydev->speed = SPEED_1000;
276 break;
277 case MIIM_88E1xxx_PHYSTAT_100:
278 phydev->speed = SPEED_100;
279 break;
280 default:
281 phydev->speed = SPEED_10;
282 break;
283 }
284
285 return 0;
286}
287
288static int m88e1011s_startup(struct phy_device *phydev)
289{
Michal Simek5ff89662016-05-18 12:46:12 +0200290 int ret;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500291
Michal Simek5ff89662016-05-18 12:46:12 +0200292 ret = genphy_update_link(phydev);
293 if (ret)
294 return ret;
295
296 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500297}
298
299/* Marvell 88E1111S */
300static int m88e1111s_config(struct phy_device *phydev)
301{
302 int reg;
303
Phil Edworthye4c26ee2016-12-12 12:54:15 +0000304 if (phy_interface_is_rgmii(phydev)) {
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000305 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100306 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000307 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
Mario Six618d42b2018-01-15 11:08:24 +0100308 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) {
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000309 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
310 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
311 reg &= ~MIIM_88E1111_TX_DELAY;
312 reg |= MIIM_88E1111_RX_DELAY;
313 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
314 reg &= ~MIIM_88E1111_RX_DELAY;
315 reg |= MIIM_88E1111_TX_DELAY;
316 }
317
318 phy_write(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100319 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000320
321 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100322 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000323
324 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
325
326 if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES)
327 reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII;
328 else
329 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII;
330
331 phy_write(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100332 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000333 }
334
335 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
336 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100337 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000338
339 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
340 reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
341 reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
342
343 phy_write(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100344 MIIM_88E1111_PHY_EXT_SR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000345 }
346
347 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
348 reg = phy_read(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100349 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000350 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
351 phy_write(phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100352 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000353
354 reg = phy_read(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100355 MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000356 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
357 MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
358 reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
359 phy_write(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100360 MIIM_88E1111_PHY_EXT_SR, reg);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000361
362 /* soft reset */
Stefan Roesed1b52822016-02-10 07:06:05 +0100363 phy_reset(phydev);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000364
365 reg = phy_read(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100366 MIIM_88E1111_PHY_EXT_SR);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000367 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
Mario Six618d42b2018-01-15 11:08:24 +0100368 MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000369 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI |
370 MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
371 phy_write(phydev, MDIO_DEVAD_NONE,
Mario Six618d42b2018-01-15 11:08:24 +0100372 MIIM_88E1111_PHY_EXT_SR, reg);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500373 }
374
Zang Roy-R6191120ffbf32011-10-27 18:52:09 +0000375 /* soft reset */
Stefan Roesed1b52822016-02-10 07:06:05 +0100376 phy_reset(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500377
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200378 marvell_of_reg_init(phydev);
379
Andy Fleming60ca78b2011-04-07 21:56:05 -0500380 genphy_config_aneg(phydev);
Stefan Roeseeb06f022016-02-10 07:06:06 +0100381 genphy_restart_aneg(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500382
383 return 0;
384}
385
Hao Zhangf0c53a42014-10-30 18:59:43 +0200386/**
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100387 * m88e151x_phy_writebits - write bits to a register
Hao Zhangf0c53a42014-10-30 18:59:43 +0200388 */
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100389void m88e151x_phy_writebits(struct phy_device *phydev,
Mario Six618d42b2018-01-15 11:08:24 +0100390 u8 reg_num, u16 offset, u16 len, u16 data)
Hao Zhangf0c53a42014-10-30 18:59:43 +0200391{
392 u16 reg, mask;
393
394 if ((len + offset) >= 16)
395 mask = 0 - (1 << offset);
396 else
397 mask = (1 << (len + offset)) - (1 << offset);
398
399 reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num);
400
401 reg &= ~mask;
402 reg |= data << offset;
403
404 phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
405}
406
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100407static int m88e151x_config(struct phy_device *phydev)
Hao Zhangf0c53a42014-10-30 18:59:43 +0200408{
Phil Edworthy19d03be2017-05-24 14:43:06 +0100409 u16 reg;
410
Hao Zhangf0c53a42014-10-30 18:59:43 +0200411 /*
412 * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512
413 * /88E1514 Rev A0, Errata Section 3.1
414 */
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200415
416 /* EEE initialization */
Joe Hershberger27a8e032016-12-09 11:54:39 -0600417 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200418 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B);
419 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
420 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28);
421 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
422 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233);
423 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D);
424 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C);
425 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
Joe Hershberger27a8e032016-12-09 11:54:39 -0600426 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200427
428 /* SGMII-to-Copper mode initialization */
Hao Zhangf0c53a42014-10-30 18:59:43 +0200429 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200430 /* Select page 18 */
Joe Hershberger27a8e032016-12-09 11:54:39 -0600431 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 18);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200432
433 /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100434 m88e151x_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
Joe Hershberger27a8e032016-12-09 11:54:39 -0600435 0, 3, MIIM_88E151x_MODE_SGMII);
Hao Zhangf0c53a42014-10-30 18:59:43 +0200436
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200437 /* PHY reset is necessary after changing MODE[2:0] */
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100438 m88e151x_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
Joe Hershberger27a8e032016-12-09 11:54:39 -0600439 MIIM_88E151x_RESET_OFFS, 1, 1);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200440
441 /* Reset page selection */
Joe Hershberger27a8e032016-12-09 11:54:39 -0600442 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0);
Clemens Gruberf10d89c2015-06-06 14:44:57 +0200443
Hao Zhangf0c53a42014-10-30 18:59:43 +0200444 udelay(100);
445 }
446
Phil Edworthy19d03be2017-05-24 14:43:06 +0100447 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
448 reg = phy_read(phydev, MDIO_DEVAD_NONE,
449 MIIM_88E1111_PHY_EXT_SR);
450
451 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
452 reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
453 reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
454
455 phy_write(phydev, MDIO_DEVAD_NONE,
456 MIIM_88E1111_PHY_EXT_SR, reg);
457 }
458
459 if (phy_interface_is_rgmii(phydev)) {
460 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 2);
461
462 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR);
463 reg &= ~MIIM_88E151x_RGMII_RXTX_DELAY;
Rufus Segarc31b36b2024-12-04 13:34:30 +0000464 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Phil Edworthy19d03be2017-05-24 14:43:06 +0100465 reg |= MIIM_88E151x_RGMII_RXTX_DELAY;
466 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
467 reg |= MIIM_88E151x_RGMII_RX_DELAY;
468 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
469 reg |= MIIM_88E151x_RGMII_TX_DELAY;
470 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR, reg);
471
472 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 0);
473 }
474
475 /* soft reset */
476 phy_reset(phydev);
477
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200478 marvell_of_reg_init(phydev);
479
Phil Edworthy19d03be2017-05-24 14:43:06 +0100480 genphy_config_aneg(phydev);
481 genphy_restart_aneg(phydev);
482
483 return 0;
Hao Zhangf0c53a42014-10-30 18:59:43 +0200484}
485
Andy Fleming60ca78b2011-04-07 21:56:05 -0500486/* Marvell 88E1118 */
487static int m88e1118_config(struct phy_device *phydev)
488{
489 /* Change Page Number */
490 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002);
491 /* Delay RGMII TX and RX */
492 phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070);
493 /* Change Page Number */
494 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003);
495 /* Adjust LED control */
496 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e);
497 /* Change Page Number */
498 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
499
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200500 marvell_of_reg_init(phydev);
501
Michal Simek0b567102016-05-18 14:46:28 +0200502 return genphy_config_aneg(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500503}
504
505static int m88e1118_startup(struct phy_device *phydev)
506{
Michal Simek5ff89662016-05-18 12:46:12 +0200507 int ret;
508
Andy Fleming60ca78b2011-04-07 21:56:05 -0500509 /* Change Page Number */
510 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
511
Michal Simek5ff89662016-05-18 12:46:12 +0200512 ret = genphy_update_link(phydev);
513 if (ret)
514 return ret;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500515
Michal Simek5ff89662016-05-18 12:46:12 +0200516 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500517}
518
519/* Marvell 88E1121R */
520static int m88e1121_config(struct phy_device *phydev)
521{
522 int pg;
523
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200524 marvell_of_reg_init(phydev);
525
Andy Fleming60ca78b2011-04-07 21:56:05 -0500526 /* Configure the PHY */
527 genphy_config_aneg(phydev);
528
529 /* Switch the page to access the led register */
530 pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE);
531 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE,
Mario Six618d42b2018-01-15 11:08:24 +0100532 MIIM_88E1121_PHY_LED_PAGE);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500533 /* Configure leds */
534 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL,
Mario Six618d42b2018-01-15 11:08:24 +0100535 MIIM_88E1121_PHY_LED_DEF);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500536 /* Restore the page pointer */
537 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg);
538
539 /* Disable IRQs and de-assert interrupt */
540 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0);
541 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS);
542
543 return 0;
544}
545
546/* Marvell 88E1145 */
547static int m88e1145_config(struct phy_device *phydev)
548{
549 int reg;
550
551 /* Errata E0, E1 */
552 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b);
553 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f);
554 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016);
555 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da);
556
557 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR,
Mario Six618d42b2018-01-15 11:08:24 +0100558 MIIM_88E1xxx_PHY_MDI_X_AUTO);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500559
560 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR);
561 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
562 reg |= MIIM_M88E1145_RGMII_RX_DELAY |
563 MIIM_M88E1145_RGMII_TX_DELAY;
564 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg);
565
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200566 marvell_of_reg_init(phydev);
567
Andy Fleming60ca78b2011-04-07 21:56:05 -0500568 genphy_config_aneg(phydev);
569
York Sunbf94cfb2017-06-06 09:22:40 -0700570 /* soft reset */
571 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
572 reg |= BMCR_RESET;
573 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500574
575 return 0;
576}
577
578static int m88e1145_startup(struct phy_device *phydev)
579{
Michal Simek5ff89662016-05-18 12:46:12 +0200580 int ret;
581
582 ret = genphy_update_link(phydev);
583 if (ret)
584 return ret;
585
Andy Fleming60ca78b2011-04-07 21:56:05 -0500586 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
Mario Six618d42b2018-01-15 11:08:24 +0100587 MIIM_88E1145_PHY_LED_DIRECT);
Michal Simek5ff89662016-05-18 12:46:12 +0200588 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500589}
590
591/* Marvell 88E1149S */
592static int m88e1149_config(struct phy_device *phydev)
593{
594 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f);
595 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
596 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5);
597 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0);
598 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
599
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200600 marvell_of_reg_init(phydev);
601
Andy Fleming60ca78b2011-04-07 21:56:05 -0500602 genphy_config_aneg(phydev);
603
604 phy_reset(phydev);
605
606 return 0;
607}
608
Stefan Roese09d5f762022-03-31 11:43:07 +0200609/* Marvell 88E1240 */
610static int m88e1240_config(struct phy_device *phydev)
611{
612 marvell_of_reg_init(phydev);
613
614 genphy_config_aneg(phydev);
615
616 return 0;
617}
618
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100619/* Marvell 88E1310 */
620static int m88e1310_config(struct phy_device *phydev)
621{
622 u16 reg;
623
624 /* LED link and activity */
625 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
626 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
627 reg = (reg & ~0xf) | 0x1;
628 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
629
630 /* Set LED2/INT to INT mode, low active */
631 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
632 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
633 reg = (reg & 0x77ff) | 0x0880;
634 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
635
636 /* Set RGMII delay */
637 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
638 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
639 reg |= 0x0030;
640 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
641
642 /* Ensure to return to page 0 */
643 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
644
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200645 marvell_of_reg_init(phydev);
646
Nathan Rossifcdcc552016-06-03 23:16:17 +1000647 return genphy_config_aneg(phydev);
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100648}
Andy Fleming60ca78b2011-04-07 21:56:05 -0500649
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100650static int m88e1680_config(struct phy_device *phydev)
651{
652 /*
653 * As per Marvell Release Notes - Alaska V 88E1680 Rev A2
654 * Errata Section 4.1
655 */
656 u16 reg;
657 int res;
658
659 /* Matrix LED mode (not neede if single LED mode is used */
660 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0004);
661 reg = phy_read(phydev, MDIO_DEVAD_NONE, 27);
662 reg |= (1 << 5);
663 phy_write(phydev, MDIO_DEVAD_NONE, 27, reg);
664
665 /* QSGMII TX amplitude change */
666 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00fd);
667 phy_write(phydev, MDIO_DEVAD_NONE, 8, 0x0b53);
668 phy_write(phydev, MDIO_DEVAD_NONE, 7, 0x200d);
669 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
670
671 /* EEE initialization */
672 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff);
673 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb030);
674 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x215c);
675 phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fc);
676 phy_write(phydev, MDIO_DEVAD_NONE, 24, 0x888c);
677 phy_write(phydev, MDIO_DEVAD_NONE, 25, 0x888c);
678 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
679 phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140);
680
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200681 marvell_of_reg_init(phydev);
682
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100683 res = genphy_config_aneg(phydev);
684 if (res < 0)
685 return res;
686
687 /* soft reset */
688 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
689 reg |= BMCR_RESET;
690 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
691
692 return 0;
693}
694
Marek Vasut5859efa2023-03-19 18:02:54 +0100695U_BOOT_PHY_DRIVER(m88e1011s) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500696 .name = "Marvell 88E1011S",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100697 .uid = MARVELL_PHY_ID_88E1101,
698 .mask = MARVELL_PHY_ID_MASK,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500699 .features = PHY_GBIT_FEATURES,
700 .config = &m88e1011s_config,
701 .startup = &m88e1011s_startup,
702 .shutdown = &genphy_shutdown,
703};
704
Marek Vasut5859efa2023-03-19 18:02:54 +0100705U_BOOT_PHY_DRIVER(m88e1111s) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500706 .name = "Marvell 88E1111S",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100707 .uid = MARVELL_PHY_ID_88E1111,
708 .mask = MARVELL_PHY_ID_MASK,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500709 .features = PHY_GBIT_FEATURES,
710 .config = &m88e1111s_config,
711 .startup = &m88e1011s_startup,
712 .shutdown = &genphy_shutdown,
713};
714
Marek Vasut5859efa2023-03-19 18:02:54 +0100715U_BOOT_PHY_DRIVER(m88e1118) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500716 .name = "Marvell 88E1118",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100717 .uid = MARVELL_PHY_ID_88E1118,
718 .mask = MARVELL_PHY_ID_MASK,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500719 .features = PHY_GBIT_FEATURES,
720 .config = &m88e1118_config,
721 .startup = &m88e1118_startup,
722 .shutdown = &genphy_shutdown,
723};
724
Marek Vasut5859efa2023-03-19 18:02:54 +0100725U_BOOT_PHY_DRIVER(m88e1118r) = {
Michal Simek130aa522012-08-07 02:23:07 +0000726 .name = "Marvell 88E1118R",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100727 .uid = MARVELL_PHY_ID_88E1116R,
728 .mask = MARVELL_PHY_ID_MASK,
Michal Simek130aa522012-08-07 02:23:07 +0000729 .features = PHY_GBIT_FEATURES,
730 .config = &m88e1118_config,
731 .startup = &m88e1118_startup,
732 .shutdown = &genphy_shutdown,
733};
734
Marek Vasut5859efa2023-03-19 18:02:54 +0100735U_BOOT_PHY_DRIVER(m88e1121r) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500736 .name = "Marvell 88E1121R",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100737 .uid = MARVELL_PHY_ID_88E1121R,
738 .mask = MARVELL_PHY_ID_MASK,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500739 .features = PHY_GBIT_FEATURES,
740 .config = &m88e1121_config,
741 .startup = &genphy_startup,
742 .shutdown = &genphy_shutdown,
743};
744
Marek Vasut5859efa2023-03-19 18:02:54 +0100745U_BOOT_PHY_DRIVER(m88e1145) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500746 .name = "Marvell 88E1145",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100747 .uid = MARVELL_PHY_ID_88E1145,
748 .mask = MARVELL_PHY_ID_MASK,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500749 .features = PHY_GBIT_FEATURES,
750 .config = &m88e1145_config,
751 .startup = &m88e1145_startup,
752 .shutdown = &genphy_shutdown,
753};
754
Marek Vasut5859efa2023-03-19 18:02:54 +0100755U_BOOT_PHY_DRIVER(m88e1149s) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500756 .name = "Marvell 88E1149S",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100757 .uid = 0x01410ca0,
758 .mask = MARVELL_PHY_ID_MASK,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500759 .features = PHY_GBIT_FEATURES,
760 .config = &m88e1149_config,
761 .startup = &m88e1011s_startup,
762 .shutdown = &genphy_shutdown,
763};
764
Marek Vasut5859efa2023-03-19 18:02:54 +0100765U_BOOT_PHY_DRIVER(m88e1240) = {
Stefan Roese09d5f762022-03-31 11:43:07 +0200766 .name = "Marvell 88E1240",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100767 .uid = MARVELL_PHY_ID_88E1240,
768 .mask = MARVELL_PHY_ID_MASK,
Stefan Roese09d5f762022-03-31 11:43:07 +0200769 .features = PHY_GBIT_FEATURES,
770 .config = &m88e1240_config,
771 .startup = &m88e1011s_startup,
772 .shutdown = &genphy_shutdown,
773};
774
Marek Vasut5859efa2023-03-19 18:02:54 +0100775U_BOOT_PHY_DRIVER(m88e151x) = {
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100776 .name = "Marvell 88E151x",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100777 .uid = MARVELL_PHY_ID_88E1510,
778 .mask = MARVELL_PHY_ID_MASK,
Michal Simek4d74cf12012-10-15 14:03:00 +0200779 .features = PHY_GBIT_FEATURES,
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100780 .config = &m88e151x_config,
Michal Simek4d74cf12012-10-15 14:03:00 +0200781 .startup = &m88e1011s_startup,
782 .shutdown = &genphy_shutdown,
Lukasz Majewski3857a162017-10-30 22:57:53 +0100783 .readext = &m88e1xxx_phy_extread,
784 .writeext = &m88e1xxx_phy_extwrite,
Michal Simek4d74cf12012-10-15 14:03:00 +0200785};
786
Marek Vasut5859efa2023-03-19 18:02:54 +0100787U_BOOT_PHY_DRIVER(m88e1310) = {
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100788 .name = "Marvell 88E1310",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100789 .uid = MARVELL_PHY_ID_88E1318S,
790 .mask = MARVELL_PHY_ID_MASK,
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100791 .features = PHY_GBIT_FEATURES,
792 .config = &m88e1310_config,
793 .startup = &m88e1011s_startup,
794 .shutdown = &genphy_shutdown,
795};
796
Marek Vasut5859efa2023-03-19 18:02:54 +0100797U_BOOT_PHY_DRIVER(m88e1680) = {
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100798 .name = "Marvell 88E1680",
Marek Vasutf7c5c232023-03-19 18:08:06 +0100799 .uid = 0x01410ed0,
800 .mask = MARVELL_PHY_ID_MASK,
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100801 .features = PHY_GBIT_FEATURES,
802 .config = &m88e1680_config,
803 .startup = &genphy_startup,
804 .shutdown = &genphy_shutdown,
805};