blob: 1a25775eee62ed44f4477588812764de4169f0e4 [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 +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;
Mario Sixc1de1312018-01-15 11:08:25 +0100464 if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
465 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Phil Edworthy19d03be2017-05-24 14:43:06 +0100466 reg |= MIIM_88E151x_RGMII_RXTX_DELAY;
467 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
468 reg |= MIIM_88E151x_RGMII_RX_DELAY;
469 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
470 reg |= MIIM_88E151x_RGMII_TX_DELAY;
471 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR, reg);
472
473 phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 0);
474 }
475
476 /* soft reset */
477 phy_reset(phydev);
478
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200479 marvell_of_reg_init(phydev);
480
Phil Edworthy19d03be2017-05-24 14:43:06 +0100481 genphy_config_aneg(phydev);
482 genphy_restart_aneg(phydev);
483
484 return 0;
Hao Zhangf0c53a42014-10-30 18:59:43 +0200485}
486
Andy Fleming60ca78b2011-04-07 21:56:05 -0500487/* Marvell 88E1118 */
488static int m88e1118_config(struct phy_device *phydev)
489{
490 /* Change Page Number */
491 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002);
492 /* Delay RGMII TX and RX */
493 phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070);
494 /* Change Page Number */
495 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003);
496 /* Adjust LED control */
497 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e);
498 /* Change Page Number */
499 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
500
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200501 marvell_of_reg_init(phydev);
502
Michal Simek0b567102016-05-18 14:46:28 +0200503 return genphy_config_aneg(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500504}
505
506static int m88e1118_startup(struct phy_device *phydev)
507{
Michal Simek5ff89662016-05-18 12:46:12 +0200508 int ret;
509
Andy Fleming60ca78b2011-04-07 21:56:05 -0500510 /* Change Page Number */
511 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
512
Michal Simek5ff89662016-05-18 12:46:12 +0200513 ret = genphy_update_link(phydev);
514 if (ret)
515 return ret;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500516
Michal Simek5ff89662016-05-18 12:46:12 +0200517 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500518}
519
520/* Marvell 88E1121R */
521static int m88e1121_config(struct phy_device *phydev)
522{
523 int pg;
524
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200525 marvell_of_reg_init(phydev);
526
Andy Fleming60ca78b2011-04-07 21:56:05 -0500527 /* Configure the PHY */
528 genphy_config_aneg(phydev);
529
530 /* Switch the page to access the led register */
531 pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE);
532 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE,
Mario Six618d42b2018-01-15 11:08:24 +0100533 MIIM_88E1121_PHY_LED_PAGE);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500534 /* Configure leds */
535 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL,
Mario Six618d42b2018-01-15 11:08:24 +0100536 MIIM_88E1121_PHY_LED_DEF);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500537 /* Restore the page pointer */
538 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg);
539
540 /* Disable IRQs and de-assert interrupt */
541 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0);
542 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS);
543
544 return 0;
545}
546
547/* Marvell 88E1145 */
548static int m88e1145_config(struct phy_device *phydev)
549{
550 int reg;
551
552 /* Errata E0, E1 */
553 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b);
554 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f);
555 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016);
556 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da);
557
558 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR,
Mario Six618d42b2018-01-15 11:08:24 +0100559 MIIM_88E1xxx_PHY_MDI_X_AUTO);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500560
561 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR);
562 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
563 reg |= MIIM_M88E1145_RGMII_RX_DELAY |
564 MIIM_M88E1145_RGMII_TX_DELAY;
565 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg);
566
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200567 marvell_of_reg_init(phydev);
568
Andy Fleming60ca78b2011-04-07 21:56:05 -0500569 genphy_config_aneg(phydev);
570
York Sunbf94cfb2017-06-06 09:22:40 -0700571 /* soft reset */
572 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
573 reg |= BMCR_RESET;
574 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500575
576 return 0;
577}
578
579static int m88e1145_startup(struct phy_device *phydev)
580{
Michal Simek5ff89662016-05-18 12:46:12 +0200581 int ret;
582
583 ret = genphy_update_link(phydev);
584 if (ret)
585 return ret;
586
Andy Fleming60ca78b2011-04-07 21:56:05 -0500587 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
Mario Six618d42b2018-01-15 11:08:24 +0100588 MIIM_88E1145_PHY_LED_DIRECT);
Michal Simek5ff89662016-05-18 12:46:12 +0200589 return m88e1xxx_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500590}
591
592/* Marvell 88E1149S */
593static int m88e1149_config(struct phy_device *phydev)
594{
595 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f);
596 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
597 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5);
598 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0);
599 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
600
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200601 marvell_of_reg_init(phydev);
602
Andy Fleming60ca78b2011-04-07 21:56:05 -0500603 genphy_config_aneg(phydev);
604
605 phy_reset(phydev);
606
607 return 0;
608}
609
Stefan Roese09d5f762022-03-31 11:43:07 +0200610/* Marvell 88E1240 */
611static int m88e1240_config(struct phy_device *phydev)
612{
613 marvell_of_reg_init(phydev);
614
615 genphy_config_aneg(phydev);
616
617 return 0;
618}
619
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100620/* Marvell 88E1310 */
621static int m88e1310_config(struct phy_device *phydev)
622{
623 u16 reg;
624
625 /* LED link and activity */
626 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
627 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
628 reg = (reg & ~0xf) | 0x1;
629 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
630
631 /* Set LED2/INT to INT mode, low active */
632 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
633 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
634 reg = (reg & 0x77ff) | 0x0880;
635 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
636
637 /* Set RGMII delay */
638 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
639 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
640 reg |= 0x0030;
641 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
642
643 /* Ensure to return to page 0 */
644 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
645
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200646 marvell_of_reg_init(phydev);
647
Nathan Rossifcdcc552016-06-03 23:16:17 +1000648 return genphy_config_aneg(phydev);
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100649}
Andy Fleming60ca78b2011-04-07 21:56:05 -0500650
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100651static int m88e1680_config(struct phy_device *phydev)
652{
653 /*
654 * As per Marvell Release Notes - Alaska V 88E1680 Rev A2
655 * Errata Section 4.1
656 */
657 u16 reg;
658 int res;
659
660 /* Matrix LED mode (not neede if single LED mode is used */
661 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0004);
662 reg = phy_read(phydev, MDIO_DEVAD_NONE, 27);
663 reg |= (1 << 5);
664 phy_write(phydev, MDIO_DEVAD_NONE, 27, reg);
665
666 /* QSGMII TX amplitude change */
667 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00fd);
668 phy_write(phydev, MDIO_DEVAD_NONE, 8, 0x0b53);
669 phy_write(phydev, MDIO_DEVAD_NONE, 7, 0x200d);
670 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
671
672 /* EEE initialization */
673 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff);
674 phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb030);
675 phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x215c);
676 phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fc);
677 phy_write(phydev, MDIO_DEVAD_NONE, 24, 0x888c);
678 phy_write(phydev, MDIO_DEVAD_NONE, 25, 0x888c);
679 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
680 phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140);
681
Stefan Roese2ae0fc22022-03-31 11:43:06 +0200682 marvell_of_reg_init(phydev);
683
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100684 res = genphy_config_aneg(phydev);
685 if (res < 0)
686 return res;
687
688 /* soft reset */
689 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
690 reg |= BMCR_RESET;
691 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
692
693 return 0;
694}
695
Andy Fleming60ca78b2011-04-07 21:56:05 -0500696static struct phy_driver M88E1011S_driver = {
697 .name = "Marvell 88E1011S",
698 .uid = 0x1410c60,
699 .mask = 0xffffff0,
700 .features = PHY_GBIT_FEATURES,
701 .config = &m88e1011s_config,
702 .startup = &m88e1011s_startup,
703 .shutdown = &genphy_shutdown,
704};
705
706static struct phy_driver M88E1111S_driver = {
707 .name = "Marvell 88E1111S",
708 .uid = 0x1410cc0,
709 .mask = 0xffffff0,
710 .features = PHY_GBIT_FEATURES,
711 .config = &m88e1111s_config,
712 .startup = &m88e1011s_startup,
713 .shutdown = &genphy_shutdown,
714};
715
716static struct phy_driver M88E1118_driver = {
717 .name = "Marvell 88E1118",
718 .uid = 0x1410e10,
719 .mask = 0xffffff0,
720 .features = PHY_GBIT_FEATURES,
721 .config = &m88e1118_config,
722 .startup = &m88e1118_startup,
723 .shutdown = &genphy_shutdown,
724};
725
Michal Simek130aa522012-08-07 02:23:07 +0000726static struct phy_driver M88E1118R_driver = {
727 .name = "Marvell 88E1118R",
728 .uid = 0x1410e40,
729 .mask = 0xffffff0,
730 .features = PHY_GBIT_FEATURES,
731 .config = &m88e1118_config,
732 .startup = &m88e1118_startup,
733 .shutdown = &genphy_shutdown,
734};
735
Andy Fleming60ca78b2011-04-07 21:56:05 -0500736static struct phy_driver M88E1121R_driver = {
737 .name = "Marvell 88E1121R",
738 .uid = 0x1410cb0,
739 .mask = 0xffffff0,
740 .features = PHY_GBIT_FEATURES,
741 .config = &m88e1121_config,
742 .startup = &genphy_startup,
743 .shutdown = &genphy_shutdown,
744};
745
746static struct phy_driver M88E1145_driver = {
747 .name = "Marvell 88E1145",
748 .uid = 0x1410cd0,
749 .mask = 0xffffff0,
750 .features = PHY_GBIT_FEATURES,
751 .config = &m88e1145_config,
752 .startup = &m88e1145_startup,
753 .shutdown = &genphy_shutdown,
754};
755
756static struct phy_driver M88E1149S_driver = {
757 .name = "Marvell 88E1149S",
758 .uid = 0x1410ca0,
759 .mask = 0xffffff0,
760 .features = PHY_GBIT_FEATURES,
761 .config = &m88e1149_config,
762 .startup = &m88e1011s_startup,
763 .shutdown = &genphy_shutdown,
764};
765
Stefan Roese09d5f762022-03-31 11:43:07 +0200766static struct phy_driver M88E1240_driver = {
767 .name = "Marvell 88E1240",
768 .uid = 0x1410e30,
769 .mask = 0xffffff0,
770 .features = PHY_GBIT_FEATURES,
771 .config = &m88e1240_config,
772 .startup = &m88e1011s_startup,
773 .shutdown = &genphy_shutdown,
774};
775
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100776static struct phy_driver M88E151x_driver = {
777 .name = "Marvell 88E151x",
Clemens Gruber89be6512015-06-06 14:44:58 +0200778 .uid = 0x1410dd0,
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100779 .mask = 0xffffff0,
Michal Simek4d74cf12012-10-15 14:03:00 +0200780 .features = PHY_GBIT_FEATURES,
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100781 .config = &m88e151x_config,
Michal Simek4d74cf12012-10-15 14:03:00 +0200782 .startup = &m88e1011s_startup,
783 .shutdown = &genphy_shutdown,
Lukasz Majewski3857a162017-10-30 22:57:53 +0100784 .readext = &m88e1xxx_phy_extread,
785 .writeext = &m88e1xxx_phy_extwrite,
Michal Simek4d74cf12012-10-15 14:03:00 +0200786};
787
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100788static struct phy_driver M88E1310_driver = {
789 .name = "Marvell 88E1310",
790 .uid = 0x01410e90,
791 .mask = 0xffffff0,
792 .features = PHY_GBIT_FEATURES,
793 .config = &m88e1310_config,
794 .startup = &m88e1011s_startup,
795 .shutdown = &genphy_shutdown,
796};
797
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100798static struct phy_driver M88E1680_driver = {
799 .name = "Marvell 88E1680",
800 .uid = 0x1410ed0,
801 .mask = 0xffffff0,
802 .features = PHY_GBIT_FEATURES,
803 .config = &m88e1680_config,
804 .startup = &genphy_startup,
805 .shutdown = &genphy_shutdown,
806};
807
Andy Fleming60ca78b2011-04-07 21:56:05 -0500808int phy_marvell_init(void)
809{
Sebastian Hesselbarth1b3352f2012-12-04 09:31:59 +0100810 phy_register(&M88E1310_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500811 phy_register(&M88E1149S_driver);
812 phy_register(&M88E1145_driver);
813 phy_register(&M88E1121R_driver);
814 phy_register(&M88E1118_driver);
Michal Simek130aa522012-08-07 02:23:07 +0000815 phy_register(&M88E1118R_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500816 phy_register(&M88E1111S_driver);
817 phy_register(&M88E1011S_driver);
Stefan Roese09d5f762022-03-31 11:43:07 +0200818 phy_register(&M88E1240_driver);
Clemens Gruber4eb793e2020-02-24 20:52:20 +0100819 phy_register(&M88E151x_driver);
Dirk Eibach4f96f3f2017-01-11 16:00:46 +0100820 phy_register(&M88E1680_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500821
822 return 0;
823}