.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Broadcom GENET MDIO routines |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2014-2017 Broadcom |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | 6 | */ |
---|
10 | 7 | |
---|
11 | | - |
---|
| 8 | +#include <linux/acpi.h> |
---|
12 | 9 | #include <linux/types.h> |
---|
13 | 10 | #include <linux/delay.h> |
---|
14 | 11 | #include <linux/wait.h> |
---|
.. | .. |
---|
98 | 95 | CMD_HD_EN | |
---|
99 | 96 | CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE); |
---|
100 | 97 | reg |= cmd_bits; |
---|
| 98 | + if (reg & CMD_SW_RESET) { |
---|
| 99 | + reg &= ~CMD_SW_RESET; |
---|
| 100 | + bcmgenet_umac_writel(priv, reg, UMAC_CMD); |
---|
| 101 | + udelay(2); |
---|
| 102 | + reg |= CMD_TX_EN | CMD_RX_EN; |
---|
| 103 | + } |
---|
101 | 104 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); |
---|
102 | 105 | } else { |
---|
103 | 106 | /* done if nothing has changed */ |
---|
.. | .. |
---|
162 | 165 | |
---|
163 | 166 | static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) |
---|
164 | 167 | { |
---|
165 | | - u32 reg; |
---|
166 | | - |
---|
167 | | - if (!GENET_IS_V5(priv)) { |
---|
168 | | - /* Speed settings are set in bcmgenet_mii_setup() */ |
---|
169 | | - reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL); |
---|
170 | | - reg |= LED_ACT_SOURCE_MAC; |
---|
171 | | - bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL); |
---|
172 | | - } |
---|
173 | | - |
---|
174 | 168 | if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) |
---|
175 | 169 | fixed_phy_set_link_update(priv->dev->phydev, |
---|
176 | 170 | bcmgenet_fixed_phy_link_update); |
---|
.. | .. |
---|
184 | 178 | const char *phy_name = NULL; |
---|
185 | 179 | u32 id_mode_dis = 0; |
---|
186 | 180 | u32 port_ctrl; |
---|
187 | | - int bmcr = -1; |
---|
188 | | - int ret; |
---|
189 | 181 | u32 reg; |
---|
190 | | - |
---|
191 | | - /* MAC clocking workaround during reset of umac state machines */ |
---|
192 | | - reg = bcmgenet_umac_readl(priv, UMAC_CMD); |
---|
193 | | - if (reg & CMD_SW_RESET) { |
---|
194 | | - /* An MII PHY must be isolated to prevent TXC contention */ |
---|
195 | | - if (priv->phy_interface == PHY_INTERFACE_MODE_MII) { |
---|
196 | | - ret = phy_read(phydev, MII_BMCR); |
---|
197 | | - if (ret >= 0) { |
---|
198 | | - bmcr = ret; |
---|
199 | | - ret = phy_write(phydev, MII_BMCR, |
---|
200 | | - bmcr | BMCR_ISOLATE); |
---|
201 | | - } |
---|
202 | | - if (ret) { |
---|
203 | | - netdev_err(dev, "failed to isolate PHY\n"); |
---|
204 | | - return ret; |
---|
205 | | - } |
---|
206 | | - } |
---|
207 | | - /* Switch MAC clocking to RGMII generated clock */ |
---|
208 | | - bcmgenet_sys_writel(priv, PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); |
---|
209 | | - /* Ensure 5 clks with Rx disabled |
---|
210 | | - * followed by 5 clks with Reset asserted |
---|
211 | | - */ |
---|
212 | | - udelay(4); |
---|
213 | | - reg &= ~(CMD_SW_RESET | CMD_LCL_LOOP_EN); |
---|
214 | | - bcmgenet_umac_writel(priv, reg, UMAC_CMD); |
---|
215 | | - /* Ensure 5 more clocks before Rx is enabled */ |
---|
216 | | - udelay(2); |
---|
217 | | - } |
---|
218 | | - |
---|
219 | | - priv->ext_phy = !priv->internal_phy && |
---|
220 | | - (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); |
---|
221 | 182 | |
---|
222 | 183 | switch (priv->phy_interface) { |
---|
223 | 184 | case PHY_INTERFACE_MODE_INTERNAL: |
---|
| 185 | + phy_name = "internal PHY"; |
---|
| 186 | + fallthrough; |
---|
224 | 187 | case PHY_INTERFACE_MODE_MOCA: |
---|
225 | 188 | /* Irrespective of the actually configured PHY speed (100 or |
---|
226 | 189 | * 1000) GENETv4 only has an internal GPHY so we will just end |
---|
.. | .. |
---|
232 | 195 | else |
---|
233 | 196 | port_ctrl = PORT_MODE_INT_EPHY; |
---|
234 | 197 | |
---|
235 | | - bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); |
---|
236 | | - |
---|
237 | | - if (priv->internal_phy) { |
---|
238 | | - phy_name = "internal PHY"; |
---|
239 | | - } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { |
---|
| 198 | + if (!phy_name) { |
---|
240 | 199 | phy_name = "MoCA"; |
---|
| 200 | + if (!GENET_IS_V5(priv)) |
---|
| 201 | + port_ctrl |= LED_ACT_SOURCE_MAC; |
---|
241 | 202 | bcmgenet_moca_phy_setup(priv); |
---|
242 | 203 | } |
---|
243 | 204 | break; |
---|
244 | 205 | |
---|
245 | 206 | case PHY_INTERFACE_MODE_MII: |
---|
246 | 207 | phy_name = "external MII"; |
---|
247 | | - phydev->supported &= PHY_BASIC_FEATURES; |
---|
248 | | - bcmgenet_sys_writel(priv, |
---|
249 | | - PORT_MODE_EXT_EPHY, SYS_PORT_CTRL); |
---|
250 | | - /* Restore the MII PHY after isolation */ |
---|
251 | | - if (bmcr >= 0) |
---|
252 | | - phy_write(phydev, MII_BMCR, bmcr); |
---|
| 208 | + phy_set_max_speed(phydev, SPEED_100); |
---|
| 209 | + port_ctrl = PORT_MODE_EXT_EPHY; |
---|
253 | 210 | break; |
---|
254 | 211 | |
---|
255 | 212 | case PHY_INTERFACE_MODE_REVMII: |
---|
.. | .. |
---|
259 | 216 | * capabilities, use that knowledge to also configure the |
---|
260 | 217 | * Reverse MII interface correctly. |
---|
261 | 218 | */ |
---|
262 | | - if (dev->phydev->supported & PHY_1000BT_FEATURES) |
---|
| 219 | + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
---|
| 220 | + dev->phydev->supported)) |
---|
263 | 221 | port_ctrl = PORT_MODE_EXT_RVMII_50; |
---|
264 | 222 | else |
---|
265 | 223 | port_ctrl = PORT_MODE_EXT_RVMII_25; |
---|
266 | | - bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); |
---|
267 | 224 | break; |
---|
268 | 225 | |
---|
269 | 226 | case PHY_INTERFACE_MODE_RGMII: |
---|
270 | 227 | /* RGMII_NO_ID: TXC transitions at the same time as TXD |
---|
271 | 228 | * (requires PCB or receiver-side delay) |
---|
272 | | - * RGMII: Add 2ns delay on TXC (90 degree shift) |
---|
273 | 229 | * |
---|
274 | 230 | * ID is implicitly disabled for 100Mbps (RG)MII operation. |
---|
275 | 231 | */ |
---|
| 232 | + phy_name = "external RGMII (no delay)"; |
---|
276 | 233 | id_mode_dis = BIT(16); |
---|
277 | | - /* fall through */ |
---|
| 234 | + port_ctrl = PORT_MODE_EXT_GPHY; |
---|
| 235 | + break; |
---|
| 236 | + |
---|
278 | 237 | case PHY_INTERFACE_MODE_RGMII_TXID: |
---|
279 | | - if (id_mode_dis) |
---|
280 | | - phy_name = "external RGMII (no delay)"; |
---|
281 | | - else |
---|
282 | | - phy_name = "external RGMII (TX delay)"; |
---|
283 | | - bcmgenet_sys_writel(priv, |
---|
284 | | - PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); |
---|
| 238 | + /* RGMII_TXID: Add 2ns delay on TXC (90 degree shift) */ |
---|
| 239 | + phy_name = "external RGMII (TX delay)"; |
---|
| 240 | + port_ctrl = PORT_MODE_EXT_GPHY; |
---|
| 241 | + break; |
---|
| 242 | + |
---|
| 243 | + case PHY_INTERFACE_MODE_RGMII_RXID: |
---|
| 244 | + phy_name = "external RGMII (RX delay)"; |
---|
| 245 | + port_ctrl = PORT_MODE_EXT_GPHY; |
---|
285 | 246 | break; |
---|
286 | 247 | default: |
---|
287 | 248 | dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface); |
---|
288 | 249 | return -EINVAL; |
---|
289 | 250 | } |
---|
290 | 251 | |
---|
| 252 | + bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); |
---|
| 253 | + |
---|
| 254 | + priv->ext_phy = !priv->internal_phy && |
---|
| 255 | + (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); |
---|
| 256 | + |
---|
291 | 257 | /* This is an external PHY (xMII), so we need to enable the RGMII |
---|
292 | 258 | * block for the interface to work |
---|
293 | 259 | */ |
---|
294 | 260 | if (priv->ext_phy) { |
---|
295 | 261 | reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); |
---|
| 262 | + reg &= ~ID_MODE_DIS; |
---|
296 | 263 | reg |= id_mode_dis; |
---|
297 | 264 | if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) |
---|
298 | 265 | reg |= RGMII_MODE_EN_V123; |
---|
.. | .. |
---|
310 | 277 | int bcmgenet_mii_probe(struct net_device *dev) |
---|
311 | 278 | { |
---|
312 | 279 | struct bcmgenet_priv *priv = netdev_priv(dev); |
---|
313 | | - struct device_node *dn = priv->pdev->dev.of_node; |
---|
| 280 | + struct device *kdev = &priv->pdev->dev; |
---|
| 281 | + struct device_node *dn = kdev->of_node; |
---|
314 | 282 | struct phy_device *phydev; |
---|
315 | 283 | u32 phy_flags = 0; |
---|
316 | 284 | int ret; |
---|
.. | .. |
---|
333 | 301 | return -ENODEV; |
---|
334 | 302 | } |
---|
335 | 303 | } else { |
---|
336 | | - phydev = dev->phydev; |
---|
| 304 | + if (has_acpi_companion(kdev)) { |
---|
| 305 | + char mdio_bus_id[MII_BUS_ID_SIZE]; |
---|
| 306 | + struct mii_bus *unimacbus; |
---|
| 307 | + |
---|
| 308 | + snprintf(mdio_bus_id, MII_BUS_ID_SIZE, "%s-%d", |
---|
| 309 | + UNIMAC_MDIO_DRV_NAME, priv->pdev->id); |
---|
| 310 | + |
---|
| 311 | + unimacbus = mdio_find_bus(mdio_bus_id); |
---|
| 312 | + if (!unimacbus) { |
---|
| 313 | + pr_err("Unable to find mii\n"); |
---|
| 314 | + return -ENODEV; |
---|
| 315 | + } |
---|
| 316 | + phydev = phy_find_first(unimacbus); |
---|
| 317 | + put_device(&unimacbus->dev); |
---|
| 318 | + if (!phydev) { |
---|
| 319 | + pr_err("Unable to find PHY\n"); |
---|
| 320 | + return -ENODEV; |
---|
| 321 | + } |
---|
| 322 | + } else { |
---|
| 323 | + phydev = dev->phydev; |
---|
| 324 | + } |
---|
337 | 325 | phydev->dev_flags = phy_flags; |
---|
338 | 326 | |
---|
339 | 327 | ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup, |
---|
.. | .. |
---|
355 | 343 | return ret; |
---|
356 | 344 | } |
---|
357 | 345 | |
---|
358 | | - phydev->advertising = phydev->supported; |
---|
| 346 | + linkmode_copy(phydev->advertising, phydev->supported); |
---|
359 | 347 | |
---|
360 | 348 | /* The internal PHY has its link interrupts routed to the |
---|
361 | 349 | * Ethernet MAC ISRs. On GENETv5 there is a hardware issue |
---|
.. | .. |
---|
458 | 446 | /* Retain this platform_device pointer for later cleanup */ |
---|
459 | 447 | priv->mii_pdev = ppdev; |
---|
460 | 448 | ppdev->dev.parent = &pdev->dev; |
---|
461 | | - ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv); |
---|
462 | | - if (pdata) |
---|
| 449 | + if (dn) |
---|
| 450 | + ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv); |
---|
| 451 | + else if (pdata) |
---|
463 | 452 | bcmgenet_mii_pdata_init(priv, &ppd); |
---|
| 453 | + else |
---|
| 454 | + ppd.phy_mask = ~0; |
---|
464 | 455 | |
---|
465 | 456 | ret = platform_device_add_resources(ppdev, &res, 1); |
---|
466 | 457 | if (ret) |
---|
.. | .. |
---|
480 | 471 | return ret; |
---|
481 | 472 | } |
---|
482 | 473 | |
---|
| 474 | +static int bcmgenet_phy_interface_init(struct bcmgenet_priv *priv) |
---|
| 475 | +{ |
---|
| 476 | + struct device *kdev = &priv->pdev->dev; |
---|
| 477 | + int phy_mode = device_get_phy_mode(kdev); |
---|
| 478 | + |
---|
| 479 | + if (phy_mode < 0) { |
---|
| 480 | + dev_err(kdev, "invalid PHY mode property\n"); |
---|
| 481 | + return phy_mode; |
---|
| 482 | + } |
---|
| 483 | + |
---|
| 484 | + priv->phy_interface = phy_mode; |
---|
| 485 | + |
---|
| 486 | + /* We need to specifically look up whether this PHY interface is |
---|
| 487 | + * internal or not *before* we even try to probe the PHY driver |
---|
| 488 | + * over MDIO as we may have shut down the internal PHY for power |
---|
| 489 | + * saving purposes. |
---|
| 490 | + */ |
---|
| 491 | + if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL) |
---|
| 492 | + priv->internal_phy = true; |
---|
| 493 | + |
---|
| 494 | + return 0; |
---|
| 495 | +} |
---|
| 496 | + |
---|
483 | 497 | static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) |
---|
484 | 498 | { |
---|
485 | 499 | struct device_node *dn = priv->pdev->dev.of_node; |
---|
486 | | - struct device *kdev = &priv->pdev->dev; |
---|
487 | 500 | struct phy_device *phydev; |
---|
488 | | - int phy_mode; |
---|
489 | 501 | int ret; |
---|
490 | 502 | |
---|
491 | 503 | /* Fetch the PHY phandle */ |
---|
.. | .. |
---|
503 | 515 | } |
---|
504 | 516 | |
---|
505 | 517 | /* Get the link mode */ |
---|
506 | | - phy_mode = of_get_phy_mode(dn); |
---|
507 | | - if (phy_mode < 0) { |
---|
508 | | - dev_err(kdev, "invalid PHY mode property\n"); |
---|
509 | | - return phy_mode; |
---|
510 | | - } |
---|
511 | | - |
---|
512 | | - priv->phy_interface = phy_mode; |
---|
513 | | - |
---|
514 | | - /* We need to specifically look up whether this PHY interface is internal |
---|
515 | | - * or not *before* we even try to probe the PHY driver over MDIO as we |
---|
516 | | - * may have shut down the internal PHY for power saving purposes. |
---|
517 | | - */ |
---|
518 | | - if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL) |
---|
519 | | - priv->internal_phy = true; |
---|
| 518 | + ret = bcmgenet_phy_interface_init(priv); |
---|
| 519 | + if (ret) |
---|
| 520 | + return ret; |
---|
520 | 521 | |
---|
521 | 522 | /* Make sure we initialize MoCA PHYs with a link down */ |
---|
522 | | - if (phy_mode == PHY_INTERFACE_MODE_MOCA) { |
---|
| 523 | + if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { |
---|
523 | 524 | phydev = of_phy_find_device(dn); |
---|
524 | 525 | if (phydev) { |
---|
525 | 526 | phydev->link = 0; |
---|
.. | .. |
---|
566 | 567 | .asym_pause = 0, |
---|
567 | 568 | }; |
---|
568 | 569 | |
---|
569 | | - phydev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL); |
---|
570 | | - if (!phydev || IS_ERR(phydev)) { |
---|
| 570 | + phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); |
---|
| 571 | + if (IS_ERR(phydev)) { |
---|
571 | 572 | dev_err(kdev, "failed to register fixed PHY device\n"); |
---|
572 | 573 | return -ENODEV; |
---|
573 | 574 | } |
---|
.. | .. |
---|
584 | 585 | |
---|
585 | 586 | static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv) |
---|
586 | 587 | { |
---|
587 | | - struct device_node *dn = priv->pdev->dev.of_node; |
---|
| 588 | + struct device *kdev = &priv->pdev->dev; |
---|
| 589 | + struct device_node *dn = kdev->of_node; |
---|
588 | 590 | |
---|
589 | 591 | if (dn) |
---|
590 | 592 | return bcmgenet_mii_of_init(priv); |
---|
| 593 | + else if (has_acpi_companion(kdev)) |
---|
| 594 | + return bcmgenet_phy_interface_init(priv); |
---|
591 | 595 | else |
---|
592 | 596 | return bcmgenet_mii_pd_init(priv); |
---|
593 | 597 | } |
---|
.. | .. |
---|
620 | 624 | if (of_phy_is_fixed_link(dn)) |
---|
621 | 625 | of_phy_deregister_fixed_link(dn); |
---|
622 | 626 | of_node_put(priv->phy_dn); |
---|
| 627 | + clk_prepare_enable(priv->clk); |
---|
623 | 628 | platform_device_unregister(priv->mii_pdev); |
---|
| 629 | + clk_disable_unprepare(priv->clk); |
---|
624 | 630 | } |
---|