@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <linux/acpi.h>
#include "sfp.h"
#include "swphy.h"
@@ -961,6 +962,95 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
}
EXPORT_SYMBOL_GPL(phylink_connect_phy);
+/**
+ * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode.
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ * @fwnode: a pointer to a &struct fwnode_handle.
+ * @flags: PHY-specific flags to communicate to the PHY device driver
+ *
+ * Connect the phy specified @fwnode to the phylink instance specified
+ * by @pl. Actions specified in phylink_connect_phy() will be
+ * performed.
+ *
+ * Returns 0 on success or a negative errno.
+ */
+int phylink_fwnode_phy_connect(struct phylink *pl,
+ struct fwnode_handle *fwnode,
+ u32 flags)
+{
+ struct device_node *dn = to_of_node(fwnode);
+ struct fwnode_reference_args args;
+ struct device_node *phy_node;
+ struct phy_device *phy_dev;
+ acpi_status status;
+ int ret;
+
+ /* Fixed links and 802.3z are handled without needing a PHY */
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
+ (pl->cfg_link_an_mode == MLO_AN_INBAND &&
+ phy_interface_mode_is_8023z(pl->link_interface)))
+ return 0;
+
+ if (is_of_node(fwnode)) {
+ phy_node = of_parse_phandle(dn, "phy-handle", 0);
+ if (!phy_node)
+ phy_node = of_parse_phandle(dn, "phy", 0);
+ if (!phy_node)
+ phy_node = of_parse_phandle(dn, "phy-device", 0);
+
+ if (!phy_node) {
+ if (pl->cfg_link_an_mode == MLO_AN_PHY)
+ return -ENODEV;
+ return 0;
+ }
+
+ phy_dev = of_phy_find_device(phy_node);
+ /* We're done with the phy_node handle */
+ of_node_put(phy_node);
+ } else if (is_acpi_node(fwnode)) {
+ status = acpi_node_get_property_reference(fwnode,
+ "phy-handle",
+ 0, &args);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ phy_dev = fwnode_phy_find_device(args.fwnode);
+ }
+ if (!phy_dev)
+ return -ENODEV;
+
+ ret = phy_attach_direct(pl->netdev, phy_dev, flags,
+ pl->link_interface);
+ if (ret)
+ return ret;
+
+ ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
+ if (ret)
+ phy_detach(phy_dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phylink_fwnode_phy_connect);
+
+/**
+ * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode.
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ * @dev: a pointer to a &struct device.
+ * @flags: PHY-specific flags to communicate to the PHY device driver
+ *
+ * Connect the phy specified @fwnode to the phylink instance specified
+ * by @pl. Actions specified in phylink_connect_phy() will be
+ * performed.
+ *
+ * Returns 0 on success or a negative errno.
+ */
+int phylink_device_phy_connect(struct phylink *pl,
+ struct device *dev,
+ u32 flags)
+{
+ return phylink_fwnode_phy_connect(pl, dev_fwnode(dev), flags);
+}
+EXPORT_SYMBOL_GPL(phylink_device_phy_connect);
+
/**
* phylink_of_phy_connect() - connect the PHY specified in the DT mode.
* @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -364,6 +364,12 @@ void phylink_add_pcs(struct phylink *, const struct phylink_pcs_ops *ops);
void phylink_destroy(struct phylink *);
int phylink_connect_phy(struct phylink *, struct phy_device *);
+int phylink_fwnode_phy_connect(struct phylink *pl,
+ struct fwnode_handle *fwnode,
+ u32 flags);
+int phylink_device_phy_connect(struct phylink *pl,
+ struct device *dev,
+ u32 flags);
int phylink_of_phy_connect(struct phylink *, struct device_node *, u32 flags);
void phylink_disconnect_phy(struct phylink *);
int phylink_fixed_state_cb(struct phylink *,
Define phylink_fwnode_phy_connect() to connect phy specified by a fwnode to a phylink instance. This function will handle both DT and ACPI nodes. Signed-off-by: Calvin Johnson <calvin.johnson@oss.nxp.com> --- drivers/net/phy/phylink.c | 90 +++++++++++++++++++++++++++++++++++++++ include/linux/phylink.h | 6 +++ 2 files changed, 96 insertions(+)