Commit db40c1aa1c100d8a9e33206575efd8b3678f31db

Authored by Hannes Schmelzer
Committed by Joe Hershberger
1 parent f8e57c650d

drivers/net/phy: add fixed-phy / fixed-link support

This patch adds support for having a "fixed-link" to some other MAC
(like some embedded switch-device).

For this purpose we introduce a new phy-driver, called "Fixed PHY".

Fixed PHY works only with CONFIG_DM_ETH enabled, since the fixed-link is
described with a subnode below ethernet interface.

Most ethernet drivers (unfortunately not all are following same scheme
for searching/attaching phys) are calling "phy_connect(...)" for getting
a phy-device.
At this point we link in, we search here for a subnode called "fixed-
link", once found we start phy_device_create(...) with the special phy-
id PHY_FIXED_ID (0xa5a55a5a).

During init the "Fixed PHY" driver has registered with this id and now
gets probed, during probe we get all the details about fixed-link out of
dts, later on the phy reports this values.

Signed-off-by: Hannes Schmelzer <hannes.schmelzer@br-automation.com>

Signed-off-by: Hannes Schmelzer <oe5hpm@oevsv.at>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>

Showing 6 changed files with 146 additions and 3 deletions Side-by-side Diff

doc/device-tree-bindings/net/fixed-link.txt
  1 +Fixed link Device Tree binding
  2 +------------------------------
  3 +
  4 +Some Ethernet MACs have a "fixed link", and are not connected to a
  5 +normal MDIO-managed PHY device. For those situations, a Device Tree
  6 +binding allows to describe a "fixed link".
  7 +
  8 +Such a fixed link situation is described by creating a 'fixed-link'
  9 +sub-node of the Ethernet MAC device node, with the following
  10 +properties:
  11 +
  12 +* 'speed' (integer, mandatory), to indicate the link speed. Accepted
  13 + values are 10, 100 and 1000
  14 +* 'full-duplex' (boolean, optional), to indicate that full duplex is
  15 + used. When absent, half duplex is assumed.
  16 +* 'pause' (boolean, optional), to indicate that pause should be
  17 + enabled.
  18 +* 'asym-pause' (boolean, optional), to indicate that asym_pause should
  19 + be enabled.
  20 +
  21 +Examples:
  22 +
  23 +ethernet@0 {
  24 + ...
  25 + fixed-link {
  26 + speed = <1000>;
  27 + full-duplex;
  28 + };
  29 + ...
  30 +};
drivers/net/phy/Kconfig
... ... @@ -90,5 +90,15 @@
90 90 config PHY_XILINX
91 91 bool "Xilinx Ethernet PHYs support"
92 92  
  93 +config PHY_FIXED
  94 + bool "Fixed-Link PHY"
  95 + depends on DM_ETH
  96 + help
  97 + Fixed PHY is used for having a 'fixed-link' to another MAC with a direct
  98 + connection (MII, RGMII, ...).
  99 + There is nothing like autoneogation and so
  100 + on, the link is always up with fixed speed and fixed duplex-setting.
  101 + More information: doc/device-tree-bindings/net/fixed-link.txt
  102 +
93 103 endif #PHYLIB
drivers/net/phy/Makefile
... ... @@ -28,4 +28,5 @@
28 28 obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
29 29 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
30 30 obj-$(CONFIG_PHY_MSCC) += mscc.o
  31 +obj-$(CONFIG_PHY_FIXED) += fixed.o
drivers/net/phy/fixed.c
  1 +/*
  2 + * Fixed-Link phy
  3 + *
  4 + * Copyright 2017 Bernecker & Rainer Industrieelektronik GmbH
  5 + *
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + */
  8 +
  9 +#include <config.h>
  10 +#include <common.h>
  11 +#include <phy.h>
  12 +#include <dm.h>
  13 +#include <fdt_support.h>
  14 +
  15 +DECLARE_GLOBAL_DATA_PTR;
  16 +
  17 +int fixedphy_probe(struct phy_device *phydev)
  18 +{
  19 + struct fixed_link *priv;
  20 + int ofnode = phydev->addr;
  21 + u32 val;
  22 +
  23 + /* check for mandatory properties within fixed-link node */
  24 + val = fdt_getprop_u32_default_node(gd->fdt_blob,
  25 + ofnode, 0, "speed", 0);
  26 + if (val != SPEED_10 && val != SPEED_100 && val != SPEED_1000) {
  27 + printf("ERROR: no/invalid speed given in fixed-link node!");
  28 + return -EINVAL;
  29 + }
  30 +
  31 + priv = malloc(sizeof(*priv));
  32 + if (!priv)
  33 + return -ENOMEM;
  34 + memset(priv, 0, sizeof(*priv));
  35 +
  36 + phydev->priv = priv;
  37 + phydev->addr = 0;
  38 +
  39 + priv->link_speed = val;
  40 + priv->duplex = fdtdec_get_bool(gd->fdt_blob, ofnode, "full-duplex");
  41 + priv->pause = fdtdec_get_bool(gd->fdt_blob, ofnode, "pause");
  42 + priv->asym_pause = fdtdec_get_bool(gd->fdt_blob, ofnode, "asym-pause");
  43 +
  44 + /* fixed-link phy must not be reset by core phy code */
  45 + phydev->flags |= PHY_FLAG_BROKEN_RESET;
  46 +
  47 + return 0;
  48 +}
  49 +
  50 +int fixedphy_startup(struct phy_device *phydev)
  51 +{
  52 + struct fixed_link *priv = phydev->priv;
  53 +
  54 + phydev->asym_pause = priv->asym_pause;
  55 + phydev->pause = priv->pause;
  56 + phydev->duplex = priv->duplex;
  57 + phydev->speed = priv->link_speed;
  58 + phydev->link = 1;
  59 +
  60 + return 0;
  61 +}
  62 +
  63 +int fixedphy_shutdown(struct phy_device *phydev)
  64 +{
  65 + return 0;
  66 +}
  67 +
  68 +static struct phy_driver fixedphy_driver = {
  69 + .uid = PHY_FIXED_ID,
  70 + .mask = 0xffffffff,
  71 + .name = "Fixed PHY",
  72 + .features = PHY_GBIT_FEATURES | SUPPORTED_MII,
  73 + .probe = fixedphy_probe,
  74 + .startup = fixedphy_startup,
  75 + .shutdown = fixedphy_shutdown,
  76 +};
  77 +
  78 +int phy_fixed_init(void)
  79 +{
  80 + phy_register(&fixedphy_driver);
  81 + return 0;
  82 +}
drivers/net/phy/phy.c
... ... @@ -515,7 +515,9 @@
515 515 #ifdef CONFIG_PHY_MSCC
516 516 phy_mscc_init();
517 517 #endif
518   -
  518 +#ifdef CONFIG_PHY_FIXED
  519 + phy_fixed_init();
  520 +#endif
519 521 return 0;
520 522 }
521 523  
522 524  
... ... @@ -854,9 +856,24 @@
854 856 struct eth_device *dev, phy_interface_t interface)
855 857 #endif
856 858 {
857   - struct phy_device *phydev;
  859 + struct phy_device *phydev = NULL;
  860 +#ifdef CONFIG_PHY_FIXED
  861 + int sn;
  862 + const char *name;
  863 + sn = fdt_first_subnode(gd->fdt_blob, dev->of_offset);
  864 + while (sn > 0) {
  865 + name = fdt_get_name(gd->fdt_blob, sn, NULL);
  866 + if (name != NULL && strcmp(name, "fixed-link") == 0) {
  867 + phydev = phy_device_create(bus,
  868 + sn, PHY_FIXED_ID, interface);
  869 + break;
  870 + }
  871 + sn = fdt_next_subnode(gd->fdt_blob, sn);
  872 + }
  873 +#endif
  874 + if (phydev == NULL)
  875 + phydev = phy_find_by_mask(bus, 1 << addr, interface);
858 876  
859   - phydev = phy_find_by_mask(bus, 1 << addr, interface);
860 877 if (phydev)
861 878 phy_connect_dev(phydev, dev);
862 879 else
... ... @@ -15,6 +15,8 @@
15 15 #include <linux/ethtool.h>
16 16 #include <linux/mdio.h>
17 17  
  18 +#define PHY_FIXED_ID 0xa5a55a5a
  19 +
18 20 #define PHY_MAX_ADDR 32
19 21  
20 22 #define PHY_FLAG_BROKEN_RESET (1 << 0) /* soft reset not supported */
... ... @@ -267,6 +269,7 @@
267 269 int phy_vitesse_init(void);
268 270 int phy_xilinx_init(void);
269 271 int phy_mscc_init(void);
  272 +int phy_fixed_init(void);
270 273  
271 274 int board_phy_config(struct phy_device *phydev);
272 275 int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);