blob: cbc365097174b3335c4a772215a113c9cfcdaeab [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Kevin Smith87b2c4e2016-03-31 19:33:12 +00002/*
3 * (C) Copyright 2015
4 * Elecsys Corporation <www.elecsyscorp.com>
5 * Kevin Smith <kevin.smith@elecsyscorp.com>
6 *
7 * Original driver:
8 * (C) Copyright 2009
9 * Marvell Semiconductor <www.marvell.com>
10 * Prafulla Wadaskar <prafulla@marvell.com>
Kevin Smith87b2c4e2016-03-31 19:33:12 +000011 */
12
13/*
14 * PHY driver for mv88e61xx ethernet switches.
15 *
16 * This driver configures the mv88e61xx for basic use as a PHY. The switch
17 * supports a VLAN configuration that determines how traffic will be routed
18 * between the ports. This driver uses a simple configuration that routes
19 * traffic from each PHY port only to the CPU port, and from the CPU port to
20 * any PHY port.
21 *
22 * The configuration determines which PHY ports to activate using the
23 * CONFIG_MV88E61XX_PHY_PORTS bitmask. Setting bit 0 will activate port 0, bit
24 * 1 activates port 1, etc. Do not set the bit for the port the CPU is
25 * connected to unless it is connected over a PHY interface (not MII).
26 *
27 * This driver was written for and tested on the mv88e6176 with an SGMII
28 * connection. Other configurations should be supported, but some additions or
29 * changes may be required.
30 */
31
32#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060033#include <log.h>
Kevin Smith87b2c4e2016-03-31 19:33:12 +000034
35#include <bitfield.h>
36#include <errno.h>
37#include <malloc.h>
38#include <miiphy.h>
39#include <netdev.h>
40
41#define PHY_AUTONEGOTIATE_TIMEOUT 5000
42
Anatolij Gustschine4779172019-10-27 01:14:37 +020043#define PORT_MASK(port_count) ((1 << (port_count)) - 1)
Kevin Smith87b2c4e2016-03-31 19:33:12 +000044
45/* Device addresses */
46#define DEVADDR_PHY(p) (p)
Kevin Smith87b2c4e2016-03-31 19:33:12 +000047#define DEVADDR_SERDES 0x0F
Kevin Smith87b2c4e2016-03-31 19:33:12 +000048
49/* SMI indirection registers for multichip addressing mode */
50#define SMI_CMD_REG 0x00
51#define SMI_DATA_REG 0x01
52
53/* Global registers */
54#define GLOBAL1_STATUS 0x00
55#define GLOBAL1_CTRL 0x04
56#define GLOBAL1_MON_CTRL 0x1A
57
58/* Global 2 registers */
59#define GLOBAL2_REG_PHY_CMD 0x18
60#define GLOBAL2_REG_PHY_DATA 0x19
61
62/* Port registers */
63#define PORT_REG_STATUS 0x00
64#define PORT_REG_PHYS_CTRL 0x01
65#define PORT_REG_SWITCH_ID 0x03
66#define PORT_REG_CTRL 0x04
67#define PORT_REG_VLAN_MAP 0x06
68#define PORT_REG_VLAN_ID 0x07
69
70/* Phy registers */
71#define PHY_REG_CTRL1 0x10
72#define PHY_REG_STATUS1 0x11
73#define PHY_REG_PAGE 0x16
74
75/* Serdes registers */
76#define SERDES_REG_CTRL_1 0x10
77
78/* Phy page numbers */
79#define PHY_PAGE_COPPER 0
80#define PHY_PAGE_SERDES 1
81
82/* Register fields */
83#define GLOBAL1_CTRL_SWRESET BIT(15)
84
85#define GLOBAL1_MON_CTRL_CPUDEST_SHIFT 4
86#define GLOBAL1_MON_CTRL_CPUDEST_WIDTH 4
87
Kevin Smith87b2c4e2016-03-31 19:33:12 +000088#define PORT_REG_STATUS_SPEED_SHIFT 8
Kevin Smith87b2c4e2016-03-31 19:33:12 +000089#define PORT_REG_STATUS_SPEED_10 0
90#define PORT_REG_STATUS_SPEED_100 1
91#define PORT_REG_STATUS_SPEED_1000 2
92
93#define PORT_REG_STATUS_CMODE_MASK 0xF
94#define PORT_REG_STATUS_CMODE_100BASE_X 0x8
95#define PORT_REG_STATUS_CMODE_1000BASE_X 0x9
96#define PORT_REG_STATUS_CMODE_SGMII 0xa
97
Chris Packham3da645f2016-08-26 17:30:26 +120098#define PORT_REG_PHYS_CTRL_PCS_AN_EN BIT(10)
99#define PORT_REG_PHYS_CTRL_PCS_AN_RST BIT(9)
100#define PORT_REG_PHYS_CTRL_FC_VALUE BIT(7)
101#define PORT_REG_PHYS_CTRL_FC_FORCE BIT(6)
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000102#define PORT_REG_PHYS_CTRL_LINK_VALUE BIT(5)
103#define PORT_REG_PHYS_CTRL_LINK_FORCE BIT(4)
Chris Packham3da645f2016-08-26 17:30:26 +1200104#define PORT_REG_PHYS_CTRL_DUPLEX_VALUE BIT(3)
105#define PORT_REG_PHYS_CTRL_DUPLEX_FORCE BIT(2)
106#define PORT_REG_PHYS_CTRL_SPD1000 BIT(1)
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200107#define PORT_REG_PHYS_CTRL_SPD100 BIT(0)
Chris Packham3da645f2016-08-26 17:30:26 +1200108#define PORT_REG_PHYS_CTRL_SPD_MASK (BIT(1) | BIT(0))
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000109
110#define PORT_REG_CTRL_PSTATE_SHIFT 0
111#define PORT_REG_CTRL_PSTATE_WIDTH 2
112
113#define PORT_REG_VLAN_ID_DEF_VID_SHIFT 0
114#define PORT_REG_VLAN_ID_DEF_VID_WIDTH 12
115
116#define PORT_REG_VLAN_MAP_TABLE_SHIFT 0
117#define PORT_REG_VLAN_MAP_TABLE_WIDTH 11
118
119#define SERDES_REG_CTRL_1_FORCE_LINK BIT(10)
120
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000121/* Field values */
122#define PORT_REG_CTRL_PSTATE_DISABLED 0
123#define PORT_REG_CTRL_PSTATE_FORWARD 3
124
125#define PHY_REG_CTRL1_ENERGY_DET_OFF 0
Anatolij Gustschinb88aeeb2019-10-27 01:14:39 +0200126#define PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE 1
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000127#define PHY_REG_CTRL1_ENERGY_DET_SENSE_ONLY 2
128#define PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT 3
129
130/* PHY Status Register */
131#define PHY_REG_STATUS1_SPEED 0xc000
132#define PHY_REG_STATUS1_GBIT 0x8000
133#define PHY_REG_STATUS1_100 0x4000
134#define PHY_REG_STATUS1_DUPLEX 0x2000
135#define PHY_REG_STATUS1_SPDDONE 0x0800
136#define PHY_REG_STATUS1_LINK 0x0400
137#define PHY_REG_STATUS1_ENERGY 0x0010
138
139/*
140 * Macros for building commands for indirect addressing modes. These are valid
141 * for both the indirect multichip addressing mode and the PHY indirection
142 * required for the writes to any PHY register.
143 */
144#define SMI_BUSY BIT(15)
145#define SMI_CMD_CLAUSE_22 BIT(12)
146#define SMI_CMD_CLAUSE_22_OP_READ (2 << 10)
147#define SMI_CMD_CLAUSE_22_OP_WRITE (1 << 10)
148
149#define SMI_CMD_READ (SMI_BUSY | SMI_CMD_CLAUSE_22 | \
150 SMI_CMD_CLAUSE_22_OP_READ)
151#define SMI_CMD_WRITE (SMI_BUSY | SMI_CMD_CLAUSE_22 | \
152 SMI_CMD_CLAUSE_22_OP_WRITE)
153
154#define SMI_CMD_ADDR_SHIFT 5
155#define SMI_CMD_ADDR_WIDTH 5
156#define SMI_CMD_REG_SHIFT 0
157#define SMI_CMD_REG_WIDTH 5
158
159/* Check for required macros */
160#ifndef CONFIG_MV88E61XX_PHY_PORTS
161#error Define CONFIG_MV88E61XX_PHY_PORTS to indicate which physical ports \
162 to activate
163#endif
164#ifndef CONFIG_MV88E61XX_CPU_PORT
165#error Define CONFIG_MV88E61XX_CPU_PORT to the port the CPU is attached to
166#endif
167
Chris Packham3da645f2016-08-26 17:30:26 +1200168/*
169 * These are ports without PHYs that may be wired directly
170 * to other serdes interfaces
171 */
172#ifndef CONFIG_MV88E61XX_FIXED_PORTS
173#define CONFIG_MV88E61XX_FIXED_PORTS 0
174#endif
175
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000176/* ID register values for different switch models */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200177#define PORT_SWITCH_ID_6020 0x0200
178#define PORT_SWITCH_ID_6070 0x0700
179#define PORT_SWITCH_ID_6071 0x0710
Chris Packhamedc42a12016-08-26 17:30:25 +1200180#define PORT_SWITCH_ID_6096 0x0980
181#define PORT_SWITCH_ID_6097 0x0990
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000182#define PORT_SWITCH_ID_6172 0x1720
183#define PORT_SWITCH_ID_6176 0x1760
Anatolij Gustschine4779172019-10-27 01:14:37 +0200184#define PORT_SWITCH_ID_6220 0x2200
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000185#define PORT_SWITCH_ID_6240 0x2400
Anatolij Gustschine4779172019-10-27 01:14:37 +0200186#define PORT_SWITCH_ID_6250 0x2500
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000187#define PORT_SWITCH_ID_6352 0x3520
188
189struct mv88e61xx_phy_priv {
190 struct mii_dev *mdio_bus;
191 int smi_addr;
192 int id;
Anatolij Gustschine4779172019-10-27 01:14:37 +0200193 int port_count; /* Number of switch ports */
194 int port_reg_base; /* Base of the switch port registers */
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200195 u16 port_stat_link_mask;/* Bitmask for port link status bits */
196 u16 port_stat_dup_mask; /* Bitmask for port duplex status bits */
197 u8 port_stat_speed_width;/* Width of speed status bitfield */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200198 u8 global1; /* Offset of Switch Global 1 registers */
199 u8 global2; /* Offset of Switch Global 2 registers */
Anatolij Gustschinb88aeeb2019-10-27 01:14:39 +0200200 u8 phy_ctrl1_en_det_shift; /* 'EDet' bit field offset */
201 u8 phy_ctrl1_en_det_width; /* Width of 'EDet' bit field */
202 u8 phy_ctrl1_en_det_ctrl; /* 'EDet' control value */
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000203};
204
205static inline int smi_cmd(int cmd, int addr, int reg)
206{
207 cmd = bitfield_replace(cmd, SMI_CMD_ADDR_SHIFT, SMI_CMD_ADDR_WIDTH,
208 addr);
209 cmd = bitfield_replace(cmd, SMI_CMD_REG_SHIFT, SMI_CMD_REG_WIDTH, reg);
210 return cmd;
211}
212
213static inline int smi_cmd_read(int addr, int reg)
214{
215 return smi_cmd(SMI_CMD_READ, addr, reg);
216}
217
218static inline int smi_cmd_write(int addr, int reg)
219{
220 return smi_cmd(SMI_CMD_WRITE, addr, reg);
221}
222
223__weak int mv88e61xx_hw_reset(struct phy_device *phydev)
224{
225 return 0;
226}
227
228/* Wait for the current SMI indirect command to complete */
229static int mv88e61xx_smi_wait(struct mii_dev *bus, int smi_addr)
230{
231 int val;
232 u32 timeout = 100;
233
234 do {
235 val = bus->read(bus, smi_addr, MDIO_DEVAD_NONE, SMI_CMD_REG);
236 if (val >= 0 && (val & SMI_BUSY) == 0)
237 return 0;
238
239 mdelay(1);
240 } while (--timeout);
241
242 puts("SMI busy timeout\n");
243 return -ETIMEDOUT;
244}
245
246/*
247 * The mv88e61xx has three types of addresses: the smi bus address, the device
248 * address, and the register address. The smi bus address distinguishes it on
249 * the smi bus from other PHYs or switches. The device address determines
250 * which on-chip register set you are reading/writing (the various PHYs, their
251 * associated ports, or global configuration registers). The register address
252 * is the offset of the register you are reading/writing.
253 *
254 * When the mv88e61xx is hardware configured to have address zero, it behaves in
255 * single-chip addressing mode, where it responds to all SMI addresses, using
256 * the smi address as its device address. This obviously only works when this
257 * is the only chip on the SMI bus. This allows the driver to access device
258 * registers without using indirection. When the chip is configured to a
259 * non-zero address, it only responds to that SMI address and requires indirect
260 * writes to access the different device addresses.
261 */
262static int mv88e61xx_reg_read(struct phy_device *phydev, int dev, int reg)
263{
264 struct mv88e61xx_phy_priv *priv = phydev->priv;
265 struct mii_dev *mdio_bus = priv->mdio_bus;
266 int smi_addr = priv->smi_addr;
267 int res;
268
269 /* In single-chip mode, the device can be addressed directly */
270 if (smi_addr == 0)
271 return mdio_bus->read(mdio_bus, dev, MDIO_DEVAD_NONE, reg);
272
273 /* Wait for the bus to become free */
274 res = mv88e61xx_smi_wait(mdio_bus, smi_addr);
275 if (res < 0)
276 return res;
277
278 /* Issue the read command */
279 res = mdio_bus->write(mdio_bus, smi_addr, MDIO_DEVAD_NONE, SMI_CMD_REG,
280 smi_cmd_read(dev, reg));
281 if (res < 0)
282 return res;
283
284 /* Wait for the read command to complete */
285 res = mv88e61xx_smi_wait(mdio_bus, smi_addr);
286 if (res < 0)
287 return res;
288
289 /* Read the data */
290 res = mdio_bus->read(mdio_bus, smi_addr, MDIO_DEVAD_NONE, SMI_DATA_REG);
291 if (res < 0)
292 return res;
293
294 return bitfield_extract(res, 0, 16);
295}
296
297/* See the comment above mv88e61xx_reg_read */
298static int mv88e61xx_reg_write(struct phy_device *phydev, int dev, int reg,
299 u16 val)
300{
301 struct mv88e61xx_phy_priv *priv = phydev->priv;
302 struct mii_dev *mdio_bus = priv->mdio_bus;
303 int smi_addr = priv->smi_addr;
304 int res;
305
306 /* In single-chip mode, the device can be addressed directly */
307 if (smi_addr == 0) {
308 return mdio_bus->write(mdio_bus, dev, MDIO_DEVAD_NONE, reg,
309 val);
310 }
311
312 /* Wait for the bus to become free */
313 res = mv88e61xx_smi_wait(mdio_bus, smi_addr);
314 if (res < 0)
315 return res;
316
317 /* Set the data to write */
318 res = mdio_bus->write(mdio_bus, smi_addr, MDIO_DEVAD_NONE,
319 SMI_DATA_REG, val);
320 if (res < 0)
321 return res;
322
323 /* Issue the write command */
324 res = mdio_bus->write(mdio_bus, smi_addr, MDIO_DEVAD_NONE, SMI_CMD_REG,
325 smi_cmd_write(dev, reg));
326 if (res < 0)
327 return res;
328
329 /* Wait for the write command to complete */
330 res = mv88e61xx_smi_wait(mdio_bus, smi_addr);
331 if (res < 0)
332 return res;
333
334 return 0;
335}
336
337static int mv88e61xx_phy_wait(struct phy_device *phydev)
338{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200339 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000340 int val;
341 u32 timeout = 100;
342
343 do {
Anatolij Gustschine4779172019-10-27 01:14:37 +0200344 val = mv88e61xx_reg_read(phydev, priv->global2,
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000345 GLOBAL2_REG_PHY_CMD);
346 if (val >= 0 && (val & SMI_BUSY) == 0)
347 return 0;
348
349 mdelay(1);
350 } while (--timeout);
351
352 return -ETIMEDOUT;
353}
354
355static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev,
356 int devad, int reg)
357{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200358 struct mv88e61xx_phy_priv *priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000359 struct phy_device *phydev;
360 int res;
361
362 phydev = (struct phy_device *)smi_wrapper->priv;
Anatolij Gustschine4779172019-10-27 01:14:37 +0200363 priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000364
365 /* Issue command to read */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200366 res = mv88e61xx_reg_write(phydev, priv->global2,
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000367 GLOBAL2_REG_PHY_CMD,
368 smi_cmd_read(dev, reg));
369
370 /* Wait for data to be read */
371 res = mv88e61xx_phy_wait(phydev);
372 if (res < 0)
373 return res;
374
375 /* Read retrieved data */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200376 return mv88e61xx_reg_read(phydev, priv->global2,
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000377 GLOBAL2_REG_PHY_DATA);
378}
379
380static int mv88e61xx_phy_write_indirect(struct mii_dev *smi_wrapper, int dev,
381 int devad, int reg, u16 data)
382{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200383 struct mv88e61xx_phy_priv *priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000384 struct phy_device *phydev;
385 int res;
386
387 phydev = (struct phy_device *)smi_wrapper->priv;
Anatolij Gustschine4779172019-10-27 01:14:37 +0200388 priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000389
390 /* Set the data to write */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200391 res = mv88e61xx_reg_write(phydev, priv->global2,
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000392 GLOBAL2_REG_PHY_DATA, data);
393 if (res < 0)
394 return res;
395 /* Issue the write command */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200396 res = mv88e61xx_reg_write(phydev, priv->global2,
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000397 GLOBAL2_REG_PHY_CMD,
398 smi_cmd_write(dev, reg));
399 if (res < 0)
400 return res;
401
402 /* Wait for command to complete */
403 return mv88e61xx_phy_wait(phydev);
404}
405
406/* Wrapper function to make calls to phy_read_indirect simpler */
407static int mv88e61xx_phy_read(struct phy_device *phydev, int phy, int reg)
408{
409 return mv88e61xx_phy_read_indirect(phydev->bus, DEVADDR_PHY(phy),
410 MDIO_DEVAD_NONE, reg);
411}
412
413/* Wrapper function to make calls to phy_read_indirect simpler */
414static int mv88e61xx_phy_write(struct phy_device *phydev, int phy,
415 int reg, u16 val)
416{
417 return mv88e61xx_phy_write_indirect(phydev->bus, DEVADDR_PHY(phy),
418 MDIO_DEVAD_NONE, reg, val);
419}
420
421static int mv88e61xx_port_read(struct phy_device *phydev, u8 port, u8 reg)
422{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200423 struct mv88e61xx_phy_priv *priv = phydev->priv;
424
425 return mv88e61xx_reg_read(phydev, priv->port_reg_base + port, reg);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000426}
427
428static int mv88e61xx_port_write(struct phy_device *phydev, u8 port, u8 reg,
429 u16 val)
430{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200431 struct mv88e61xx_phy_priv *priv = phydev->priv;
432
433 return mv88e61xx_reg_write(phydev, priv->port_reg_base + port,
434 reg, val);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000435}
436
437static int mv88e61xx_set_page(struct phy_device *phydev, u8 phy, u8 page)
438{
439 return mv88e61xx_phy_write(phydev, phy, PHY_REG_PAGE, page);
440}
441
442static int mv88e61xx_get_switch_id(struct phy_device *phydev)
443{
444 int res;
445
446 res = mv88e61xx_port_read(phydev, 0, PORT_REG_SWITCH_ID);
447 if (res < 0)
448 return res;
449 return res & 0xfff0;
450}
451
452static bool mv88e61xx_6352_family(struct phy_device *phydev)
453{
454 struct mv88e61xx_phy_priv *priv = phydev->priv;
455
456 switch (priv->id) {
457 case PORT_SWITCH_ID_6172:
458 case PORT_SWITCH_ID_6176:
459 case PORT_SWITCH_ID_6240:
460 case PORT_SWITCH_ID_6352:
461 return true;
462 }
463 return false;
464}
465
466static int mv88e61xx_get_cmode(struct phy_device *phydev, u8 port)
467{
468 int res;
469
470 res = mv88e61xx_port_read(phydev, port, PORT_REG_STATUS);
471 if (res < 0)
472 return res;
473 return res & PORT_REG_STATUS_CMODE_MASK;
474}
475
476static int mv88e61xx_parse_status(struct phy_device *phydev)
477{
478 unsigned int speed;
479 unsigned int mii_reg;
480
481 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, PHY_REG_STATUS1);
482
483 if ((mii_reg & PHY_REG_STATUS1_LINK) &&
484 !(mii_reg & PHY_REG_STATUS1_SPDDONE)) {
485 int i = 0;
486
487 puts("Waiting for PHY realtime link");
488 while (!(mii_reg & PHY_REG_STATUS1_SPDDONE)) {
489 /* Timeout reached ? */
490 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
491 puts(" TIMEOUT !\n");
492 phydev->link = 0;
493 break;
494 }
495
496 if ((i++ % 1000) == 0)
497 putc('.');
498 udelay(1000);
499 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
500 PHY_REG_STATUS1);
501 }
502 puts(" done\n");
503 udelay(500000); /* another 500 ms (results in faster booting) */
504 } else {
505 if (mii_reg & PHY_REG_STATUS1_LINK)
506 phydev->link = 1;
507 else
508 phydev->link = 0;
509 }
510
511 if (mii_reg & PHY_REG_STATUS1_DUPLEX)
512 phydev->duplex = DUPLEX_FULL;
513 else
514 phydev->duplex = DUPLEX_HALF;
515
516 speed = mii_reg & PHY_REG_STATUS1_SPEED;
517
518 switch (speed) {
519 case PHY_REG_STATUS1_GBIT:
520 phydev->speed = SPEED_1000;
521 break;
522 case PHY_REG_STATUS1_100:
523 phydev->speed = SPEED_100;
524 break;
525 default:
526 phydev->speed = SPEED_10;
527 break;
528 }
529
530 return 0;
531}
532
533static int mv88e61xx_switch_reset(struct phy_device *phydev)
534{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200535 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000536 int time;
537 int val;
538 u8 port;
539
540 /* Disable all ports */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200541 for (port = 0; port < priv->port_count; port++) {
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000542 val = mv88e61xx_port_read(phydev, port, PORT_REG_CTRL);
543 if (val < 0)
544 return val;
545 val = bitfield_replace(val, PORT_REG_CTRL_PSTATE_SHIFT,
546 PORT_REG_CTRL_PSTATE_WIDTH,
547 PORT_REG_CTRL_PSTATE_DISABLED);
548 val = mv88e61xx_port_write(phydev, port, PORT_REG_CTRL, val);
549 if (val < 0)
550 return val;
551 }
552
553 /* Wait 2 ms for queues to drain */
554 udelay(2000);
555
556 /* Reset switch */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200557 val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_CTRL);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000558 if (val < 0)
559 return val;
560 val |= GLOBAL1_CTRL_SWRESET;
Anatolij Gustschine4779172019-10-27 01:14:37 +0200561 val = mv88e61xx_reg_write(phydev, priv->global1,
562 GLOBAL1_CTRL, val);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000563 if (val < 0)
564 return val;
565
566 /* Wait up to 1 second for switch reset complete */
567 for (time = 1000; time; time--) {
Anatolij Gustschine4779172019-10-27 01:14:37 +0200568 val = mv88e61xx_reg_read(phydev, priv->global1,
569 GLOBAL1_CTRL);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000570 if (val >= 0 && ((val & GLOBAL1_CTRL_SWRESET) == 0))
571 break;
572 udelay(1000);
573 }
574 if (!time)
575 return -ETIMEDOUT;
576
577 return 0;
578}
579
580static int mv88e61xx_serdes_init(struct phy_device *phydev)
581{
582 int val;
583
584 val = mv88e61xx_set_page(phydev, DEVADDR_SERDES, PHY_PAGE_SERDES);
585 if (val < 0)
586 return val;
587
588 /* Power up serdes module */
589 val = mv88e61xx_phy_read(phydev, DEVADDR_SERDES, MII_BMCR);
590 if (val < 0)
591 return val;
592 val &= ~(BMCR_PDOWN);
593 val = mv88e61xx_phy_write(phydev, DEVADDR_SERDES, MII_BMCR, val);
594 if (val < 0)
595 return val;
596
597 return 0;
598}
599
600static int mv88e61xx_port_enable(struct phy_device *phydev, u8 port)
601{
602 int val;
603
604 val = mv88e61xx_port_read(phydev, port, PORT_REG_CTRL);
605 if (val < 0)
606 return val;
607 val = bitfield_replace(val, PORT_REG_CTRL_PSTATE_SHIFT,
608 PORT_REG_CTRL_PSTATE_WIDTH,
609 PORT_REG_CTRL_PSTATE_FORWARD);
610 val = mv88e61xx_port_write(phydev, port, PORT_REG_CTRL, val);
611 if (val < 0)
612 return val;
613
614 return 0;
615}
616
617static int mv88e61xx_port_set_vlan(struct phy_device *phydev, u8 port,
Chris Packhamedc42a12016-08-26 17:30:25 +1200618 u16 mask)
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000619{
620 int val;
621
622 /* Set VID to port number plus one */
623 val = mv88e61xx_port_read(phydev, port, PORT_REG_VLAN_ID);
624 if (val < 0)
625 return val;
626 val = bitfield_replace(val, PORT_REG_VLAN_ID_DEF_VID_SHIFT,
627 PORT_REG_VLAN_ID_DEF_VID_WIDTH,
628 port + 1);
629 val = mv88e61xx_port_write(phydev, port, PORT_REG_VLAN_ID, val);
630 if (val < 0)
631 return val;
632
633 /* Set VID mask */
634 val = mv88e61xx_port_read(phydev, port, PORT_REG_VLAN_MAP);
635 if (val < 0)
636 return val;
637 val = bitfield_replace(val, PORT_REG_VLAN_MAP_TABLE_SHIFT,
638 PORT_REG_VLAN_MAP_TABLE_WIDTH,
639 mask);
640 val = mv88e61xx_port_write(phydev, port, PORT_REG_VLAN_MAP, val);
641 if (val < 0)
642 return val;
643
644 return 0;
645}
646
647static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port)
648{
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200649 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000650 int res;
651 int val;
652 bool forced = false;
653
654 val = mv88e61xx_port_read(phydev, port, PORT_REG_STATUS);
655 if (val < 0)
656 return val;
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200657 if (!(val & priv->port_stat_link_mask)) {
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000658 /* Temporarily force link to read port configuration */
659 u32 timeout = 100;
660 forced = true;
661
662 val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL);
663 if (val < 0)
664 return val;
665 val |= (PORT_REG_PHYS_CTRL_LINK_FORCE |
666 PORT_REG_PHYS_CTRL_LINK_VALUE);
667 val = mv88e61xx_port_write(phydev, port, PORT_REG_PHYS_CTRL,
668 val);
669 if (val < 0)
670 return val;
671
672 /* Wait for status register to reflect forced link */
673 do {
674 val = mv88e61xx_port_read(phydev, port,
675 PORT_REG_STATUS);
Tom Rini09418652017-05-08 22:14:32 -0400676 if (val < 0) {
677 res = -EIO;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000678 goto unforce;
Tom Rini09418652017-05-08 22:14:32 -0400679 }
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200680 if (val & priv->port_stat_link_mask)
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000681 break;
682 } while (--timeout);
683
684 if (timeout == 0) {
685 res = -ETIMEDOUT;
686 goto unforce;
687 }
688 }
689
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200690 if (val & priv->port_stat_dup_mask)
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000691 phydev->duplex = DUPLEX_FULL;
692 else
693 phydev->duplex = DUPLEX_HALF;
694
695 val = bitfield_extract(val, PORT_REG_STATUS_SPEED_SHIFT,
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200696 priv->port_stat_speed_width);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000697 switch (val) {
698 case PORT_REG_STATUS_SPEED_1000:
699 phydev->speed = SPEED_1000;
700 break;
701 case PORT_REG_STATUS_SPEED_100:
702 phydev->speed = SPEED_100;
703 break;
704 default:
705 phydev->speed = SPEED_10;
706 break;
707 }
708
709 res = 0;
710
711unforce:
712 if (forced) {
713 val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL);
714 if (val < 0)
715 return val;
716 val &= ~(PORT_REG_PHYS_CTRL_LINK_FORCE |
717 PORT_REG_PHYS_CTRL_LINK_VALUE);
718 val = mv88e61xx_port_write(phydev, port, PORT_REG_PHYS_CTRL,
719 val);
720 if (val < 0)
721 return val;
722 }
723
724 return res;
725}
726
Chris Packham21788612018-06-03 16:21:26 +1200727static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
728{
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200729 struct mv88e61xx_phy_priv *priv = phydev->priv;
Chris Packham21788612018-06-03 16:21:26 +1200730 int val;
731
732 val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL);
733 if (val < 0)
734 return val;
735
736 val &= ~(PORT_REG_PHYS_CTRL_SPD_MASK |
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200737 PORT_REG_PHYS_CTRL_FC_VALUE |
738 PORT_REG_PHYS_CTRL_FC_FORCE);
739 val |= PORT_REG_PHYS_CTRL_FC_FORCE |
Chris Packham21788612018-06-03 16:21:26 +1200740 PORT_REG_PHYS_CTRL_DUPLEX_VALUE |
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200741 PORT_REG_PHYS_CTRL_DUPLEX_FORCE;
742
743 if (priv->id == PORT_SWITCH_ID_6071) {
744 val |= PORT_REG_PHYS_CTRL_SPD100;
745 } else {
746 val |= PORT_REG_PHYS_CTRL_PCS_AN_EN |
747 PORT_REG_PHYS_CTRL_PCS_AN_RST |
748 PORT_REG_PHYS_CTRL_SPD1000;
749 }
Chris Packham21788612018-06-03 16:21:26 +1200750
751 if (port == CONFIG_MV88E61XX_CPU_PORT)
752 val |= PORT_REG_PHYS_CTRL_LINK_VALUE |
753 PORT_REG_PHYS_CTRL_LINK_FORCE;
754
755 return mv88e61xx_port_write(phydev, port, PORT_REG_PHYS_CTRL,
756 val);
757}
758
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000759static int mv88e61xx_set_cpu_port(struct phy_device *phydev)
760{
Anatolij Gustschine4779172019-10-27 01:14:37 +0200761 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000762 int val;
763
764 /* Set CPUDest */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200765 val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_MON_CTRL);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000766 if (val < 0)
767 return val;
768 val = bitfield_replace(val, GLOBAL1_MON_CTRL_CPUDEST_SHIFT,
769 GLOBAL1_MON_CTRL_CPUDEST_WIDTH,
770 CONFIG_MV88E61XX_CPU_PORT);
Anatolij Gustschine4779172019-10-27 01:14:37 +0200771 val = mv88e61xx_reg_write(phydev, priv->global1,
772 GLOBAL1_MON_CTRL, val);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000773 if (val < 0)
774 return val;
775
776 /* Allow CPU to route to any port */
Anatolij Gustschine4779172019-10-27 01:14:37 +0200777 val = PORT_MASK(priv->port_count) & ~(1 << CONFIG_MV88E61XX_CPU_PORT);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000778 val = mv88e61xx_port_set_vlan(phydev, CONFIG_MV88E61XX_CPU_PORT, val);
779 if (val < 0)
780 return val;
781
782 /* Enable CPU port */
783 val = mv88e61xx_port_enable(phydev, CONFIG_MV88E61XX_CPU_PORT);
784 if (val < 0)
785 return val;
786
787 val = mv88e61xx_read_port_config(phydev, CONFIG_MV88E61XX_CPU_PORT);
788 if (val < 0)
789 return val;
790
791 /* If CPU is connected to serdes, initialize serdes */
792 if (mv88e61xx_6352_family(phydev)) {
793 val = mv88e61xx_get_cmode(phydev, CONFIG_MV88E61XX_CPU_PORT);
794 if (val < 0)
795 return val;
796 if (val == PORT_REG_STATUS_CMODE_100BASE_X ||
797 val == PORT_REG_STATUS_CMODE_1000BASE_X ||
798 val == PORT_REG_STATUS_CMODE_SGMII) {
799 val = mv88e61xx_serdes_init(phydev);
800 if (val < 0)
801 return val;
802 }
Chris Packham21788612018-06-03 16:21:26 +1200803 } else {
804 val = mv88e61xx_fixed_port_setup(phydev,
805 CONFIG_MV88E61XX_CPU_PORT);
806 if (val < 0)
807 return val;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000808 }
809
810 return 0;
811}
812
813static int mv88e61xx_switch_init(struct phy_device *phydev)
814{
815 static int init;
816 int res;
817
818 if (init)
819 return 0;
820
821 res = mv88e61xx_switch_reset(phydev);
822 if (res < 0)
823 return res;
824
825 res = mv88e61xx_set_cpu_port(phydev);
826 if (res < 0)
827 return res;
828
829 init = 1;
830
831 return 0;
832}
833
834static int mv88e61xx_phy_enable(struct phy_device *phydev, u8 phy)
835{
836 int val;
837
838 val = mv88e61xx_phy_read(phydev, phy, MII_BMCR);
839 if (val < 0)
840 return val;
841 val &= ~(BMCR_PDOWN);
842 val = mv88e61xx_phy_write(phydev, phy, MII_BMCR, val);
843 if (val < 0)
844 return val;
845
846 return 0;
847}
848
849static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy)
850{
Anatolij Gustschinb88aeeb2019-10-27 01:14:39 +0200851 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000852 int val;
853
854 /*
855 * Enable energy-detect sensing on PHY, used to determine when a PHY
856 * port is physically connected
857 */
858 val = mv88e61xx_phy_read(phydev, phy, PHY_REG_CTRL1);
859 if (val < 0)
860 return val;
Anatolij Gustschinb88aeeb2019-10-27 01:14:39 +0200861 val = bitfield_replace(val, priv->phy_ctrl1_en_det_shift,
862 priv->phy_ctrl1_en_det_width,
863 priv->phy_ctrl1_en_det_ctrl);
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000864 val = mv88e61xx_phy_write(phydev, phy, PHY_REG_CTRL1, val);
865 if (val < 0)
866 return val;
867
868 return 0;
869}
870
871static int mv88e61xx_phy_config_port(struct phy_device *phydev, u8 phy)
872{
873 int val;
874
875 val = mv88e61xx_port_enable(phydev, phy);
876 if (val < 0)
877 return val;
878
879 val = mv88e61xx_port_set_vlan(phydev, phy,
880 1 << CONFIG_MV88E61XX_CPU_PORT);
881 if (val < 0)
882 return val;
883
884 return 0;
885}
886
Anatolij Gustschine4779172019-10-27 01:14:37 +0200887/*
888 * This function is used to pre-configure the required register
889 * offsets, so that the indirect register access to the PHY registers
890 * is possible. This is necessary to be able to read the PHY ID
891 * while driver probing or in get_phy_id(). The globalN register
892 * offsets must be initialized correctly for a detected switch,
893 * otherwise detection of the PHY ID won't work!
894 */
895static int mv88e61xx_priv_reg_offs_pre_init(struct phy_device *phydev)
896{
897 struct mv88e61xx_phy_priv *priv = phydev->priv;
898
899 /*
900 * Initial 'port_reg_base' value must be an offset of existing
901 * port register, then reading the ID should succeed. First, try
902 * to read via port registers with device address 0x10 (88E6096
903 * and compatible switches).
904 */
905 priv->port_reg_base = 0x10;
906 priv->id = mv88e61xx_get_switch_id(phydev);
907 if (priv->id != 0xfff0) {
908 priv->global1 = 0x1B;
909 priv->global2 = 0x1C;
910 return 0;
911 }
912
913 /*
914 * Now try via port registers with device address 0x08
915 * (88E6020 and compatible switches).
916 */
917 priv->port_reg_base = 0x08;
918 priv->id = mv88e61xx_get_switch_id(phydev);
919 if (priv->id != 0xfff0) {
920 priv->global1 = 0x0F;
921 priv->global2 = 0x07;
922 return 0;
923 }
924
925 debug("%s Unknown ID 0x%x\n", __func__, priv->id);
926 return -ENODEV;
927}
928
Kevin Smith87b2c4e2016-03-31 19:33:12 +0000929static int mv88e61xx_probe(struct phy_device *phydev)
930{
931 struct mii_dev *smi_wrapper;
932 struct mv88e61xx_phy_priv *priv;
933 int res;
934
935 res = mv88e61xx_hw_reset(phydev);
936 if (res < 0)
937 return res;
938
939 priv = malloc(sizeof(*priv));
940 if (!priv)
941 return -ENOMEM;
942
943 memset(priv, 0, sizeof(*priv));
944
945 /*
946 * This device requires indirect reads/writes to the PHY registers
947 * which the generic PHY code can't handle. Make a wrapper MII device
948 * to handle reads/writes
949 */
950 smi_wrapper = mdio_alloc();
951 if (!smi_wrapper) {
952 free(priv);
953 return -ENOMEM;
954 }
955
956 /*
957 * Store the mdio bus in the private data, as we are going to replace
958 * the bus with the wrapper bus
959 */
960 priv->mdio_bus = phydev->bus;
961
962 /*
963 * Store the smi bus address in private data. This lets us use the
964 * phydev addr field for device address instead, as the genphy code
965 * expects.
966 */
967 priv->smi_addr = phydev->addr;
968
969 /*
970 * Store the phy_device in the wrapper mii device. This lets us get it
971 * back when genphy functions call phy_read/phy_write.
972 */
973 smi_wrapper->priv = phydev;
974 strncpy(smi_wrapper->name, "indirect mii", sizeof(smi_wrapper->name));
975 smi_wrapper->read = mv88e61xx_phy_read_indirect;
976 smi_wrapper->write = mv88e61xx_phy_write_indirect;
977
978 /* Replace the bus with the wrapper device */
979 phydev->bus = smi_wrapper;
980
981 phydev->priv = priv;
982
Anatolij Gustschine4779172019-10-27 01:14:37 +0200983 res = mv88e61xx_priv_reg_offs_pre_init(phydev);
984 if (res < 0)
985 return res;
986
987 debug("%s ID 0x%x\n", __func__, priv->id);
988
989 switch (priv->id) {
990 case PORT_SWITCH_ID_6096:
991 case PORT_SWITCH_ID_6097:
992 case PORT_SWITCH_ID_6172:
993 case PORT_SWITCH_ID_6176:
994 case PORT_SWITCH_ID_6240:
995 case PORT_SWITCH_ID_6352:
996 priv->port_count = 11;
Anatolij Gustschin2eadde42019-10-27 01:14:38 +0200997 priv->port_stat_link_mask = BIT(11);
998 priv->port_stat_dup_mask = BIT(10);
999 priv->port_stat_speed_width = 2;
Anatolij Gustschinb88aeeb2019-10-27 01:14:39 +02001000 priv->phy_ctrl1_en_det_shift = 8;
1001 priv->phy_ctrl1_en_det_width = 2;
1002 priv->phy_ctrl1_en_det_ctrl =
1003 PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT;
Anatolij Gustschine4779172019-10-27 01:14:37 +02001004 break;
1005 case PORT_SWITCH_ID_6020:
1006 case PORT_SWITCH_ID_6070:
1007 case PORT_SWITCH_ID_6071:
1008 case PORT_SWITCH_ID_6220:
1009 case PORT_SWITCH_ID_6250:
1010 priv->port_count = 7;
Anatolij Gustschin2eadde42019-10-27 01:14:38 +02001011 priv->port_stat_link_mask = BIT(12);
1012 priv->port_stat_dup_mask = BIT(9);
1013 priv->port_stat_speed_width = 1;
Anatolij Gustschinb88aeeb2019-10-27 01:14:39 +02001014 priv->phy_ctrl1_en_det_shift = 14;
1015 priv->phy_ctrl1_en_det_width = 1;
1016 priv->phy_ctrl1_en_det_ctrl =
1017 PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE;
Anatolij Gustschine4779172019-10-27 01:14:37 +02001018 break;
1019 default:
1020 free(priv);
1021 return -ENODEV;
1022 }
1023
1024 res = mdio_register(smi_wrapper);
1025 if (res)
1026 printf("Failed to register SMI bus\n");
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001027
1028 return 0;
1029}
1030
1031static int mv88e61xx_phy_config(struct phy_device *phydev)
1032{
Anatolij Gustschine4779172019-10-27 01:14:37 +02001033 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001034 int res;
1035 int i;
1036 int ret = -1;
1037
1038 res = mv88e61xx_switch_init(phydev);
1039 if (res < 0)
1040 return res;
1041
Anatolij Gustschine4779172019-10-27 01:14:37 +02001042 for (i = 0; i < priv->port_count; i++) {
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001043 if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) {
1044 phydev->addr = i;
1045
1046 res = mv88e61xx_phy_enable(phydev, i);
1047 if (res < 0) {
1048 printf("Error enabling PHY %i\n", i);
1049 continue;
1050 }
1051 res = mv88e61xx_phy_setup(phydev, i);
1052 if (res < 0) {
1053 printf("Error setting up PHY %i\n", i);
1054 continue;
1055 }
1056 res = mv88e61xx_phy_config_port(phydev, i);
1057 if (res < 0) {
1058 printf("Error configuring PHY %i\n", i);
1059 continue;
1060 }
1061
Tim Harvey6e434b92019-02-04 12:56:52 -08001062 res = phy_reset(phydev);
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001063 if (res < 0) {
Tim Harvey6e434b92019-02-04 12:56:52 -08001064 printf("Error resetting PHY %i\n", i);
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001065 continue;
1066 }
Tim Harvey6e434b92019-02-04 12:56:52 -08001067 res = genphy_config_aneg(phydev);
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001068 if (res < 0) {
Tim Harvey6e434b92019-02-04 12:56:52 -08001069 printf("Error setting PHY %i autoneg\n", i);
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001070 continue;
1071 }
1072
1073 /* Return success if any PHY succeeds */
1074 ret = 0;
Chris Packham3da645f2016-08-26 17:30:26 +12001075 } else if ((1 << i) & CONFIG_MV88E61XX_FIXED_PORTS) {
1076 res = mv88e61xx_fixed_port_setup(phydev, i);
1077 if (res < 0) {
1078 printf("Error configuring port %i\n", i);
1079 continue;
1080 }
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001081 }
1082 }
1083
1084 return ret;
1085}
1086
1087static int mv88e61xx_phy_is_connected(struct phy_device *phydev)
1088{
1089 int val;
1090
1091 val = mv88e61xx_phy_read(phydev, phydev->addr, PHY_REG_STATUS1);
1092 if (val < 0)
1093 return 0;
1094
1095 /*
1096 * After reset, the energy detect signal remains high for a few seconds
1097 * regardless of whether a cable is connected. This function will
1098 * return false positives during this time.
1099 */
1100 return (val & PHY_REG_STATUS1_ENERGY) == 0;
1101}
1102
1103static int mv88e61xx_phy_startup(struct phy_device *phydev)
1104{
Anatolij Gustschine4779172019-10-27 01:14:37 +02001105 struct mv88e61xx_phy_priv *priv = phydev->priv;
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001106 int i;
1107 int link = 0;
1108 int res;
1109 int speed = phydev->speed;
1110 int duplex = phydev->duplex;
1111
Anatolij Gustschine4779172019-10-27 01:14:37 +02001112 for (i = 0; i < priv->port_count; i++) {
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001113 if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) {
1114 phydev->addr = i;
1115 if (!mv88e61xx_phy_is_connected(phydev))
1116 continue;
1117 res = genphy_update_link(phydev);
1118 if (res < 0)
1119 continue;
1120 res = mv88e61xx_parse_status(phydev);
1121 if (res < 0)
1122 continue;
1123 link = (link || phydev->link);
1124 }
1125 }
1126 phydev->link = link;
1127
1128 /* Restore CPU interface speed and duplex after it was changed for
1129 * other ports */
1130 phydev->speed = speed;
1131 phydev->duplex = duplex;
1132
1133 return 0;
1134}
1135
1136static struct phy_driver mv88e61xx_driver = {
1137 .name = "Marvell MV88E61xx",
1138 .uid = 0x01410eb1,
1139 .mask = 0xfffffff0,
1140 .features = PHY_GBIT_FEATURES,
1141 .probe = mv88e61xx_probe,
1142 .config = mv88e61xx_phy_config,
1143 .startup = mv88e61xx_phy_startup,
1144 .shutdown = &genphy_shutdown,
1145};
1146
Chris Packhamedc42a12016-08-26 17:30:25 +12001147static struct phy_driver mv88e609x_driver = {
1148 .name = "Marvell MV88E609x",
1149 .uid = 0x1410c89,
1150 .mask = 0xfffffff0,
1151 .features = PHY_GBIT_FEATURES,
1152 .probe = mv88e61xx_probe,
1153 .config = mv88e61xx_phy_config,
1154 .startup = mv88e61xx_phy_startup,
1155 .shutdown = &genphy_shutdown,
1156};
1157
Anatolij Gustschinb8b125a2019-10-27 01:14:40 +02001158static struct phy_driver mv88e6071_driver = {
1159 .name = "Marvell MV88E6071",
1160 .uid = 0x1410db0,
1161 .mask = 0xfffffff0,
1162 .features = PHY_BASIC_FEATURES | SUPPORTED_MII,
1163 .probe = mv88e61xx_probe,
1164 .config = mv88e61xx_phy_config,
1165 .startup = mv88e61xx_phy_startup,
1166 .shutdown = &genphy_shutdown,
1167};
1168
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001169int phy_mv88e61xx_init(void)
1170{
1171 phy_register(&mv88e61xx_driver);
Chris Packhamedc42a12016-08-26 17:30:25 +12001172 phy_register(&mv88e609x_driver);
Anatolij Gustschinb8b125a2019-10-27 01:14:40 +02001173 phy_register(&mv88e6071_driver);
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001174
1175 return 0;
1176}
1177
1178/*
1179 * Overload weak get_phy_id definition since we need non-standard functions
1180 * to read PHY registers
1181 */
1182int get_phy_id(struct mii_dev *bus, int smi_addr, int devad, u32 *phy_id)
1183{
1184 struct phy_device temp_phy;
1185 struct mv88e61xx_phy_priv temp_priv;
1186 struct mii_dev temp_mii;
1187 int val;
1188
1189 /*
1190 * Buid temporary data structures that the chip reading code needs to
1191 * read the ID
1192 */
1193 temp_priv.mdio_bus = bus;
1194 temp_priv.smi_addr = smi_addr;
1195 temp_phy.priv = &temp_priv;
1196 temp_mii.priv = &temp_phy;
1197
Anatolij Gustschine4779172019-10-27 01:14:37 +02001198 /*
1199 * get_phy_id() can be called by framework before mv88e61xx driver
1200 * probing, in this case the global register offsets are not
1201 * initialized yet. Do this initialization here before indirect
1202 * PHY register access.
1203 */
1204 val = mv88e61xx_priv_reg_offs_pre_init(&temp_phy);
1205 if (val < 0)
1206 return val;
1207
Kevin Smith87b2c4e2016-03-31 19:33:12 +00001208 val = mv88e61xx_phy_read_indirect(&temp_mii, 0, devad, MII_PHYSID1);
1209 if (val < 0)
1210 return -EIO;
1211
1212 *phy_id = val << 16;
1213
1214 val = mv88e61xx_phy_read_indirect(&temp_mii, 0, devad, MII_PHYSID2);
1215 if (val < 0)
1216 return -EIO;
1217
1218 *phy_id |= (val & 0xffff);
1219
1220 return 0;
1221}