Commit 970cb1ce authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'phy-package'



Christian Marangi says:

====================
net: phy: Introduce PHY Package concept

Idea of this big series is to introduce the concept of PHY package in DT
and give PHY drivers a way to derive the base address from DT.

The concept of PHY package is nothing new and is already a thing in the
kernel with the API phy_package_join/leave/read/write.

What is currently lacking is describing this in DT and better reference
a base address to calculate offset from.

In the scenario of a PHY package where multiple address are used and
there isn't a way to get the base address of the PHY package from some
regs, getting the information from DT is the only way.

A possible example to this problem is this:

        ethernet-phy-package@0 {
            compatible = "qcom,qca8075-package";
            #address-cells = <1>;
            #size-cells = <0>;

            reg = <0>;
            qcom,package-mode = "qsgmii";

            ethernet-phy@1 {
              reg = <1>;
            };

            phy4: ethernet-phy@4 {
              reg = <4>;
            };
        };

The mdio parse functions are changed to address for this additional
special node, the function is changed to simply detect this node and
search also in this. (we match the node name to be "ethernet-phy-package")

PHY driver can then use introduced helper of_phy_package_join to join the
PHY to the PHY package and derive the base address from DT.

Changes v7:
- Rebase on top of net-next
- Add Reviewed-by tag for DT patch
- Change tx-driver-strength to tx-drive-strength
- Drop driver reference in DT
Changes v6:
- Back to absolute PHY implementation
- Correctly drop refcount for node on error condition and on PHY leave
- Drop DT include patch in favor for 3 boolean vendor property
- Fix Documentation problem for compatible and missing type and
  description
- Drop redundand gpio-controller dependency and description
- Skip scanphy with invalid PHY Package node and make reg mandatory
- Rework fiber read status to use more generic function
- Split qca808x LED generalization patch to permit easier review
- Correctly return -EINVAL with wrong data passed to vendor property
- Drop removing LED ops for qca807x PHY driver with gpio-controller
Changes v5:
- Rebase on top of net-next
- Change implementation to base addr + offset in subnode
- Adapt to all the changes and cleanup done to at803x
Changes v4:
- Rework DT implementation
- Drop of autojoin support and rework to simple helper
- Rework PHY driver to the new implementation
- Add compatible for qca807x package
- Further cleanup patches
Changes v3:
- Add back compatible implementation
- Detach patch that can be handled separately (phy_package_mmd,
  phy_package extended)
- Rework code to new simplified implementation with base addr + offset
- Improve documentation with additional info and description
Changes v2:
- Drop compatible "ethernet-phy-package", use node name prefix matching
  instead
- Improve DT example
- Add reg for ethernet-phy-package
- Drop phy-mode for ethernet-phy-package
- Drop patch for generalization of phy-mode
- Drop global-phy property (handle internally to the PHY driver)
- Rework OF phy package code and PHY driver to handle base address
- Fix missing of_node_put
- Add some missing docs for added variables in struct
- Move some define from dt-bindings include to PHY driver
- Handle qsgmii validation in PHY driver
- Fix wrong include for gpiolib
- Drop reduntant version.h include
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b63cc733 f508a226
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/ethernet-phy-package.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Ethernet PHY Package Common Properties

maintainers:
  - Christian Marangi <ansuelsmth@gmail.com>

description:
  PHY packages are multi-port Ethernet PHY of the same family
  and each Ethernet PHY is affected by the global configuration
  of the PHY package.

  Each reg of the PHYs defined in the PHY package node is
  absolute and describe the real address of the Ethernet PHY on
  the MDIO bus.

properties:
  $nodename:
    pattern: "^ethernet-phy-package@[a-f0-9]+$"

  reg:
    minimum: 0
    maximum: 31
    description:
      The base ID number for the PHY package.
      Commonly the ID of the first PHY in the PHY package.

      Some PHY in the PHY package might be not defined but
      still occupy ID on the device (just not attached to
      anything) hence the PHY package reg might correspond
      to a not attached PHY (offset 0).

  '#address-cells':
    const: 1

  '#size-cells':
    const: 0

patternProperties:
  ^ethernet-phy@[a-f0-9]+$:
    $ref: ethernet-phy.yaml#

required:
  - reg
  - '#address-cells'
  - '#size-cells'

additionalProperties: true
+184 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/qcom,qca807x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Qualcomm QCA807x Ethernet PHY

maintainers:
  - Christian Marangi <ansuelsmth@gmail.com>
  - Robert Marko <robert.marko@sartura.hr>

description: |
  Qualcomm QCA8072/5 Ethernet PHY is PHY package of 2 or 5
  IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and
  1000BASE-T PHY-s.

  They feature 2 SerDes, one for PSGMII or QSGMII connection with
  MAC, while second one is SGMII for connection to MAC or fiber.

  Both models have a combo port that supports 1000BASE-X and
  100BASE-FX fiber.

  Each PHY inside of QCA807x series has 4 digitally controlled
  output only pins that natively drive LED-s for up to 2 attached
  LEDs. Some vendor also use these 4 output for GPIO usage without
  attaching LEDs.

  Note that output pins can be set to drive LEDs OR GPIO, mixed
  definition are not accepted.

$ref: ethernet-phy-package.yaml#

properties:
  compatible:
    enum:
      - qcom,qca8072-package
      - qcom,qca8075-package

  qcom,package-mode:
    description: |
      PHY package can be configured in 3 mode following this table:

                    First Serdes mode       Second Serdes mode
      Option 1      PSGMII for copper       Disabled
                    ports 0-4
      Option 2      PSGMII for copper       1000BASE-X / 100BASE-FX
                    ports 0-4
      Option 3      QSGMII for copper       SGMII for
                    ports 0-3               copper port 4

      PSGMII mode (option 1 or 2) is configured dynamically based on
      the presence of a connected SFP device.
    $ref: /schemas/types.yaml#/definitions/string
    enum:
      - qsgmii
      - psgmii
    default: psgmii

  qcom,tx-drive-strength-milliwatt:
    description: set the TX Amplifier value in mv.
    $ref: /schemas/types.yaml#/definitions/uint32
    enum: [140, 160, 180, 200, 220,
           240, 260, 280, 300, 320,
           400, 500, 600]
    default: 600

patternProperties:
  ^ethernet-phy@[a-f0-9]+$:
    $ref: ethernet-phy.yaml#

    properties:
      qcom,dac-full-amplitude:
        description:
          Set Analog MDI driver amplitude to FULL.

          With this not defined, amplitude is set to DSP.
          (amplitude is adjusted based on cable length)

          With this enabled and qcom,dac-full-bias-current
          and qcom,dac-disable-bias-current-tweak disabled,
          bias current is half.
        type: boolean

      qcom,dac-full-bias-current:
        description:
          Set Analog MDI driver bias current to FULL.

          With this not defined, bias current is set to DSP.
          (bias current is adjusted based on cable length)

          Actual bias current might be different with
          qcom,dac-disable-bias-current-tweak disabled.
        type: boolean

      qcom,dac-disable-bias-current-tweak:
        description: |
          Set Analog MDI driver bias current to disable tweak
          to bias current.

          With this not defined, bias current tweak are enabled
          by default.

          With this enabled the following tweak are NOT applied:
          - With both FULL amplitude and FULL bias current: bias current
            is set to half.
          - With only DSP amplitude: bias current is set to half and
            is set to 1/4 with cable < 10m.
          - With DSP bias current (included both DSP amplitude and
            DSP bias current): bias current is half the detected current
            with cable < 10m.
        type: boolean

      gpio-controller: true

      '#gpio-cells':
        const: 2

    if:
      required:
        - gpio-controller
    then:
      properties:
        leds: false

    unevaluatedProperties: false

required:
  - compatible

unevaluatedProperties: false

examples:
  - |
    #include <dt-bindings/leds/common.h>

    mdio {
        #address-cells = <1>;
        #size-cells = <0>;

        ethernet-phy-package@0 {
            #address-cells = <1>;
            #size-cells = <0>;
            compatible = "qcom,qca8075-package";
            reg = <0>;

            qcom,package-mode = "qsgmii";

            ethernet-phy@0 {
                reg = <0>;

                leds {
                    #address-cells = <1>;
                    #size-cells = <0>;

                    led@0 {
                        reg = <0>;
                        color = <LED_COLOR_ID_GREEN>;
                        function = LED_FUNCTION_LAN;
                        default-state = "keep";
                    };
                };
            };

            ethernet-phy@1 {
                reg = <1>;
            };

            ethernet-phy@2 {
                reg = <2>;

                gpio-controller;
                #gpio-cells = <2>;
            };

            ethernet-phy@3 {
                reg = <3>;
            };

            ethernet-phy@4 {
                reg = <4>;
            };
        };
    };
+56 −23
Original line number Diff line number Diff line
@@ -139,6 +139,53 @@ bool of_mdiobus_child_is_phy(struct device_node *child)
}
EXPORT_SYMBOL(of_mdiobus_child_is_phy);

static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np,
				   bool *scanphys)
{
	struct device_node *child;
	int addr, rc = 0;

	/* Loop over the child nodes and register a phy_device for each phy */
	for_each_available_child_of_node(np, child) {
		if (of_node_name_eq(child, "ethernet-phy-package")) {
			/* Ignore invalid ethernet-phy-package node */
			if (!of_property_present(child, "reg"))
				continue;

			rc = __of_mdiobus_parse_phys(mdio, child, NULL);
			if (rc && rc != -ENODEV)
				goto exit;

			continue;
		}

		addr = of_mdio_parse_addr(&mdio->dev, child);
		if (addr < 0) {
			/* Skip scanning for invalid ethernet-phy-package node */
			if (scanphys)
				*scanphys = true;
			continue;
		}

		if (of_mdiobus_child_is_phy(child))
			rc = of_mdiobus_register_phy(mdio, child, addr);
		else
			rc = of_mdiobus_register_device(mdio, child, addr);

		if (rc == -ENODEV)
			dev_err(&mdio->dev,
				"MDIO device at address %d is missing.\n",
				addr);
		else if (rc)
			goto exit;
	}

	return 0;
exit:
	of_node_put(child);
	return rc;
}

/**
 * __of_mdiobus_register - Register mii_bus and create PHYs from the device tree
 * @mdio: pointer to mii_bus structure
@@ -180,33 +227,18 @@ int __of_mdiobus_register(struct mii_bus *mdio, struct device_node *np,
		return rc;

	/* Loop over the child nodes and register a phy_device for each phy */
	for_each_available_child_of_node(np, child) {
		addr = of_mdio_parse_addr(&mdio->dev, child);
		if (addr < 0) {
			scanphys = true;
			continue;
		}

		if (of_mdiobus_child_is_phy(child))
			rc = of_mdiobus_register_phy(mdio, child, addr);
		else
			rc = of_mdiobus_register_device(mdio, child, addr);

		if (rc == -ENODEV)
			dev_err(&mdio->dev,
				"MDIO device at address %d is missing.\n",
				addr);
		else if (rc)
	rc = __of_mdiobus_parse_phys(mdio, np, &scanphys);
	if (rc)
		goto unregister;
	}

	if (!scanphys)
		return 0;

	/* auto scan for PHYs with empty reg property */
	for_each_available_child_of_node(np, child) {
		/* Skip PHYs with reg property set */
		if (of_property_present(child, "reg"))
		/* Skip PHYs with reg property set or ethernet-phy-package node */
		if (of_property_present(child, "reg") ||
		    of_node_name_eq(child, "ethernet-phy-package"))
			continue;

		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
@@ -227,15 +259,16 @@ int __of_mdiobus_register(struct mii_bus *mdio, struct device_node *np,
				if (!rc)
					break;
				if (rc != -ENODEV)
					goto unregister;
					goto put_unregister;
			}
		}
	}

	return 0;

unregister:
put_unregister:
	of_node_put(child);
unregister:
	mdiobus_unregister(mdio);
	return rc;
}
+2 −1
Original line number Diff line number Diff line
@@ -665,10 +665,11 @@ static int bcm54616s_config_aneg(struct phy_device *phydev)
static int bcm54616s_read_status(struct phy_device *phydev)
{
	struct bcm54616s_phy_priv *priv = phydev->priv;
	bool changed;
	int err;

	if (priv->mode_1000bx_en)
		err = genphy_c37_read_status(phydev);
		err = genphy_c37_read_status(phydev, &changed);
	else
		err = genphy_read_status(phydev);

+36 −8
Original line number Diff line number Diff line
@@ -459,19 +459,34 @@ EXPORT_SYMBOL(of_mdio_find_bus);
 * found, set the of_node pointer for the mdio device. This allows
 * auto-probed phy devices to be supplied with information passed in
 * via DT.
 * If a PHY package is found, PHY is searched also there.
 */
static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
				    struct mdio_device *mdiodev)
static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev,
			       struct device_node *np)
{
	struct device *dev = &mdiodev->dev;
	struct device_node *child;

	if (dev->of_node || !bus->dev.of_node)
		return;

	for_each_available_child_of_node(bus->dev.of_node, child) {
	for_each_available_child_of_node(np, child) {
		int addr;

		if (of_node_name_eq(child, "ethernet-phy-package")) {
			/* Validate PHY package reg presence */
			if (!of_property_present(child, "reg")) {
				of_node_put(child);
				return -EINVAL;
			}

			if (!of_mdiobus_find_phy(dev, mdiodev, child)) {
				/* The refcount for the PHY package will be
				 * incremented later when PHY join the Package.
				 */
				of_node_put(child);
				return 0;
			}

			continue;
		}

		addr = of_mdio_parse_addr(dev, child);
		if (addr < 0)
			continue;
@@ -481,9 +496,22 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
			/* The refcount on "child" is passed to the mdio
			 * device. Do _not_ use of_node_put(child) here.
			 */
			return;
			return 0;
		}
	}

	return -ENODEV;
}

static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
				    struct mdio_device *mdiodev)
{
	struct device *dev = &mdiodev->dev;

	if (dev->of_node || !bus->dev.of_node)
		return;

	of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node);
}
#else /* !IS_ENABLED(CONFIG_OF_MDIO) */
static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
Loading