From patchwork Mon Dec 18 09:17:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcin Wojtas X-Patchwork-Id: 10118555 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 92C8B60390 for ; Mon, 18 Dec 2017 09:20:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7D49020415 for ; Mon, 18 Dec 2017 09:20:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F1E628ECC; Mon, 18 Dec 2017 09:20:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CD59E28DC5 for ; Mon, 18 Dec 2017 09:20:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=b098vlbfvcLPhCg9HbghShq7/uYJOXcDu+vVF60iiIE=; b=MXuROpM1xSv8QopugQMjTNVZD3 cm4rN30fLKpiaxVNpPDwV2HqDqQ8GfPsC2B5yoHMNT/rozWn80suY76MhVbo4SNg8lS7MG/Quw1Pr 6yuO9iXNRg96px3lP7ikS6y36e9iWP0VYnMwmcojjNNp8P6GTjkfxGgjdfA0KlMAQQL1HKIQbbvTT heBqR6Q9UjNEdTymyZnqLsN6pKIcqo4FoqrhsvhnSdq7RkzDFAbFMlQoCY08dQOep0k7v+Y1/Qv0Z FU4LUQ3dgRTnbzvBP9xzcWHXcGsQZTP93xiY4uVyI9kSYDdLyeFb8C75intXv/0Ve5n7+OahFF11g wjLm4ltg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1eQraz-0007ug-AH; Mon, 18 Dec 2017 09:20:25 +0000 Received: from mail-lf0-x242.google.com ([2a00:1450:4010:c07::242]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1eQrZG-0005Lj-OU for linux-arm-kernel@lists.infradead.org; Mon, 18 Dec 2017 09:18:52 +0000 Received: by mail-lf0-x242.google.com with SMTP id f18so16912234lfg.8 for ; Mon, 18 Dec 2017 01:18:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=semihalf-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=nZXLnhvx8/k0Slp956fn6z70v5P0yCSUD84icDu3ebs=; b=dnNIolbBgajQTxkgCBWIWJWNlBvBBBS/uRjHopX4qe3Qap34uhj2Y/v2ktlTlMrC/f fDEMIo2MstvCLu0lIhSf1vSWQY1Mf2tKbrilyf0KQdw14vrvcoH77C3pvkbUTj8HoPNZ EVToi1X8WI5X5eZcEyMDVEjoKZttdEFtexMaLs1zUFC6L5/O53PhhcFa3fnuag522LtD DSHPoqIm3JkQIs5AkRLwkGjHZxi/9Hip3BbNvQsWHfVlZK1ZUzxZ8baMYqdV/ddWbMc/ z49jHaFMzxWknQTw4JPF1fN+ymIsVRJMnNNIXvStktxSDU6uba+Jgom+lkMOprJEx+vs Raug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=nZXLnhvx8/k0Slp956fn6z70v5P0yCSUD84icDu3ebs=; b=bhJefTSiTT/zIJWnOC5pqmHNLSOlRgaPjw4FePithMv0sxYASQ49DBzy2c1xoh66ST FWcyz6DVlOCewwmF8rdYV650XlMX9xlvQNltLAo8nvM3zssSXkV3uUPK/yAy35xQaeYu csoJlSYEKrRkJWIj8Tb5zB/6CSC7PZ1D+q45N9K9LW5fQkLNy8mmNhe1LYzjvrxyvYYQ 2Pydoy5OAm+jM99S6jI8+0AQpxn1bPtOg/phlW4G2E/NMN1FXHHxqdz6T6UYcffK9nh5 BgaYzJFGS5RO40IPw7ilXVT/aVmNLnVzFx+cC4Nqk0EyFKmWPU3UsI09ZWOs5DL0DX+q mqBw== X-Gm-Message-State: AKGB3mJ9ip95nxwcvzN2W48uSa5G9ZCrYNa1FTLi03K52tOT/m34lQ7f G6DnIk6Czs+SY4A1xO3OXzHnrg== X-Google-Smtp-Source: ACJfBosnDihjbFvf6KiqNV+1QmEe0B2xqnim4FBPnJ8L0o+rhKWsB07j5xq7uMX/OGnRKsqOycPaeg== X-Received: by 10.46.84.65 with SMTP id y1mr10870599ljd.74.1513588696489; Mon, 18 Dec 2017 01:18:16 -0800 (PST) Received: from gilgamesh.semihalf.com (31-172-191-173.noc.fibertech.net.pl. [31.172.191.173]) by smtp.gmail.com with ESMTPSA id r16sm2407186ljd.18.2017.12.18.01.18.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 18 Dec 2017 01:18:15 -0800 (PST) From: Marcin Wojtas To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org Subject: [net-next: PATCH 3/8] mdio_bus: Introduce fwnode MDIO helpers Date: Mon, 18 Dec 2017 10:17:59 +0100 Message-Id: <1513588684-15647-4-git-send-email-mw@semihalf.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1513588684-15647-1-git-send-email-mw@semihalf.com> References: <1513588684-15647-1-git-send-email-mw@semihalf.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20171218_011839_893272_7245DE08 X-CRM114-Status: GOOD ( 17.61 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thomas.petazzoni@free-electrons.com, andrew@lunn.ch, f.fainelli@gmail.com, linux@arm.linux.org.uk, ard.biesheuvel@linaro.org, jaz@semihalf.com, antoine.tenart@free-electrons.com, rafael.j.wysocki@intel.com, nadavh@marvell.com, neta@marvell.com, ezequiel.garcia@free-electrons.com, tn@semihalf.com, gregory.clement@free-electrons.com, mw@semihalf.com, davem@davemloft.net MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This patch introduces fwnode helper for registering MDIO bus, as well as one for finding the PHY, basing on its firmware node pointer. Comparing to existing OF equivalent, fwnode_mdiobus_register() does not support: * deprecated bindings (device whitelist, nor the PHY ID embedded in the compatible string) * MDIO bus auto scanning Signed-off-by: Marcin Wojtas --- drivers/net/phy/mdio_bus.c | 218 ++++++++++++++++++++ include/linux/mdio.h | 3 + 2 files changed, 221 insertions(+) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index a0f34c3..f2b2a94 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -662,6 +663,223 @@ static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static int fwnode_mdiobus_register_phy(struct mii_bus *bus, + struct fwnode_handle *child, u32 addr) +{ + struct phy_device *phy; + bool is_c45 = false; + int rc; + + rc = fwnode_property_match_string(child, "compatible", + "ethernet-phy-ieee802.3-c45"); + if (!rc) + is_c45 = true; + + phy = get_phy_device(bus, addr, is_c45); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy->irq = bus->irq[addr]; + + if (to_of_node(child)) { + rc = of_irq_get(to_of_node(child), 0); + if (rc == -EPROBE_DEFER) { + phy_device_free(phy); + return rc; + } else if (rc > 0) { + phy->irq = rc; + bus->irq[addr] = rc; + } + } + + if (fwnode_property_read_bool(child, "broken-turn-around")) + bus->phy_ignore_ta_mask |= 1 << addr; + + /* Associate the fwnode with the device structure so it + * can be looked up later. + */ + phy->mdio.dev.fwnode = child; + + /* All data is now stored in the phy struct, so register it */ + rc = phy_device_register(phy); + if (rc) { + phy_device_free(phy); + fwnode_handle_put(child); + return rc; + } + + dev_dbg(&bus->dev, "registered phy at address %i\n", addr); + + return 0; +} + +static int fwnode_mdiobus_register_device(struct mii_bus *bus, + struct fwnode_handle *child, u32 addr) +{ + struct mdio_device *mdiodev; + int rc; + + mdiodev = mdio_device_create(bus, addr); + if (IS_ERR(mdiodev)) + return PTR_ERR(mdiodev); + + /* Associate the fwnode with the device structure so it + * can be looked up later. + */ + mdiodev->dev.fwnode = child; + + /* All data is now stored in the mdiodev struct; register it. */ + rc = mdio_device_register(mdiodev); + if (rc) { + mdio_device_free(mdiodev); + fwnode_handle_put(child); + return rc; + } + + dev_dbg(&bus->dev, "registered mdio device at address %i\n", addr); + + return 0; +} + +static int fwnode_mdio_parse_addr(struct device *dev, + const struct fwnode_handle *fwnode) +{ + u32 addr; + int ret; + + ret = fwnode_property_read_u32(fwnode, "reg", &addr); + if (ret < 0) { + dev_err(dev, "PHY node has no 'reg' property\n"); + return ret; + } + + /* A PHY must have a reg property in the range [0-31] */ + if (addr < 0 || addr >= PHY_MAX_ADDR) { + dev_err(dev, "PHY address %i is invalid\n", addr); + return -EINVAL; + } + + return addr; +} + +/** + * fwnode_mdiobus_child_is_phy - Return true if the child is a PHY node. + * It must either: + * o Compatible string of "ethernet-phy-ieee802.3-c45" + * o Compatible string of "ethernet-phy-ieee802.3-c22" + * Checking "compatible" property is done, in order to follow the DT binding. + */ +static bool fwnode_mdiobus_child_is_phy(struct fwnode_handle *child) +{ + int ret; + + ret = fwnode_property_match_string(child, "compatible", + "ethernet-phy-ieee802.3-c45"); + if (!ret) + return true; + + ret = fwnode_property_match_string(child, "compatible", + "ethernet-phy-ieee802.3-c22"); + if (!ret) + return true; + + if (!fwnode_property_present(child, "compatible")) + return true; + + return false; +} + +/** + * fwnode_mdiobus_register - Register mii_bus and create PHYs from the fwnode + * @bus: pointer to mii_bus structure + * @fwnode: pointer to fwnode_handle of MDIO bus. + * + * This function registers the mii_bus structure and registers a phy_device + * for each child node of @fwnode. + */ +int fwnode_mdiobus_register(struct mii_bus *bus, struct fwnode_handle *fwnode) +{ + struct fwnode_handle *child; + int addr, rc; + int default_gpio_reset_delay_ms = 10; + + /* Do not continue if the node is disabled */ + if (!fwnode_device_is_available(fwnode)) + return -ENODEV; + + /* Mask out all PHYs from auto probing. Instead the PHYs listed in + * the firmware nodes are populated after the bus has been registered. + */ + bus->phy_mask = ~0; + + bus->dev.fwnode = fwnode; + + /* Get bus level PHY reset GPIO details */ + bus->reset_delay_us = default_gpio_reset_delay_ms; + fwnode_property_read_u32(fwnode, "reset-delay-us", + &bus->reset_delay_us); + + /* Register the MDIO bus */ + rc = mdiobus_register(bus); + if (rc) + return rc; + + /* Loop over the child nodes and register a phy_device for each PHY */ + fwnode_for_each_child_node(fwnode, child) { + addr = fwnode_mdio_parse_addr(&bus->dev, child); + if (addr < 0) + continue; + + if (fwnode_mdiobus_child_is_phy(child)) + rc = fwnode_mdiobus_register_phy(bus, child, addr); + else + rc = fwnode_mdiobus_register_device(bus, child, addr); + if (rc) + goto unregister; + } + + return 0; + +unregister: + mdiobus_unregister(bus); + + return rc; +} +EXPORT_SYMBOL(fwnode_mdiobus_register); + +/* Helper function for fwnode_phy_find_device */ +static int fwnode_phy_match(struct device *dev, void *phy_fwnode) +{ + return dev->fwnode == phy_fwnode; +} + +/** + * fwnode_phy_find_device - find the phy_device associated to fwnode + * @phy_fwnode: Pointer to the PHY's fwnode + * + * If successful, returns a pointer to the phy_device with the embedded + * struct device refcount incremented by one, or NULL on failure. + */ +struct phy_device *fwnode_phy_find_device(struct fwnode_handle *phy_fwnode) +{ + struct device *d; + struct mdio_device *mdiodev; + + if (!phy_fwnode) + return NULL; + + d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, fwnode_phy_match); + if (d) { + mdiodev = to_mdio_device(d); + if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) + return to_phy_device(d); + put_device(d); + } + + return NULL; +} +EXPORT_SYMBOL(fwnode_phy_find_device); + #ifdef CONFIG_PM static int mdio_bus_suspend(struct device *dev) { diff --git a/include/linux/mdio.h b/include/linux/mdio.h index e37c21d..286ec12 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -272,6 +272,9 @@ int mdiobus_unregister_device(struct mdio_device *mdiodev); bool mdiobus_is_registered_device(struct mii_bus *bus, int addr); struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr); +int fwnode_mdiobus_register(struct mii_bus *bus, struct fwnode_handle *fwnode); +struct phy_device *fwnode_phy_find_device(struct fwnode_handle *phy_fwnode); + /** * mdio_module_driver() - Helper macro for registering mdio drivers *