From patchwork Fri Oct 23 10:56:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 288151 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55516C388F9 for ; Fri, 23 Oct 2020 10:56:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0B4C821D43 for ; Fri, 23 Oct 2020 10:56:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S462622AbgJWK45 (ORCPT ); Fri, 23 Oct 2020 06:56:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S462583AbgJWK4k (ORCPT ); Fri, 23 Oct 2020 06:56:40 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D4F6C0613CE for ; Fri, 23 Oct 2020 03:56:40 -0700 (PDT) Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVukG-00087n-Kp; Fri, 23 Oct 2020 12:56:28 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1kVukF-0001k9-D5; Fri, 23 Oct 2020 12:56:27 +0200 From: Oleksij Rempel To: Andrew Lunn , "David S. Miller" , Florian Fainelli , Heiner Kallweit , Jakub Kicinski , Oliver Hartkopp Cc: Oleksij Rempel , David Jander , kernel@pengutronix.de, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Russell King , mkl@pengutronix.de, Marek Vasut , linux-can@vger.kernel.org Subject: [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Date: Fri, 23 Oct 2020 12:56:21 +0200 Message-Id: <20201023105626.6534-2-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201023105626.6534-1-o.rempel@pengutronix.de> References: <20201023105626.6534-1-o.rempel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Most of CAN PHYs (transceivers) are not attached to any data bus, so we are not able to communicate with them. For this case, we introduce a CAN specific virtual bus to make use of existing PHY framework. Signed-off-by: Oleksij Rempel --- drivers/net/phy/Kconfig | 8 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/can_phy_bus.c | 196 ++++++++++++++++++++++++++++++++++ include/linux/can/phy.h | 21 ++++ 4 files changed, 226 insertions(+) create mode 100644 drivers/net/phy/can_phy_bus.c create mode 100644 include/linux/can/phy.h diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 698bea312adc..39e3f57ea60a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -153,6 +153,14 @@ config BCM_CYGNUS_PHY config BCM_NET_PHYLIB tristate +config CAN_PHY_BUS + tristate "Virtual CAN PHY Bus" + depends on PHYLIB + help + Most CAN PHYs (transceivers) are not attached to any data bus, so we + are not able to communicate with them. For this case, a CAN specific + virtual bus to make use of existing PHY framework. + config CICADA_PHY tristate "Cicada PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a13e402074cf..0d76d802c07f 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o +obj-$(CONFIG_CAN_PHY_BUS) += can_phy_bus.o obj-$(CONFIG_CICADA_PHY) += cicada.o obj-$(CONFIG_CORTINA_PHY) += cortina.o obj-$(CONFIG_DAVICOM_PHY) += davicom.o diff --git a/drivers/net/phy/can_phy_bus.c b/drivers/net/phy/can_phy_bus.c new file mode 100644 index 000000000000..b1712e19327c --- /dev/null +++ b/drivers/net/phy/can_phy_bus.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2020 Oleksij Rempel , Pengutronix + +#include +#include +#include +#include +#include +#include + +struct can_mdio_bus { + struct mii_bus *mii_bus; + struct list_head phys; +}; + +struct can_phy { + int addr; + struct phy_device *phydev; + struct list_head node; +}; + +static struct platform_device *pdev; +static struct can_mdio_bus platform_fmb = { + .phys = LIST_HEAD_INIT(platform_fmb.phys), +}; + +static DEFINE_IDA(phy_can_ida); + +/* The is the fake bus. All read/write operations are bugs. */ +static int can_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) +{ + WARN_ON_ONCE(1); + return 0xFFFF; +} + +static int can_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num, + u16 val) +{ + WARN_ON_ONCE(1); + return 0; +} + +static int can_phy_add(int phy_addr) +{ + struct can_mdio_bus *fmb = &platform_fmb; + struct can_phy *fp; + + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; + + fp->addr = phy_addr; + + list_add_tail(&fp->node, &fmb->phys); + + return 0; +} + +static void can_phy_del(int phy_addr) +{ + struct can_mdio_bus *fmb = &platform_fmb; + struct can_phy *fp, *tmp; + + list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { + if (fp->addr == phy_addr) { + list_del(&fp->node); + kfree(fp); + ida_simple_remove(&phy_can_ida, phy_addr); + return; + } + } +} + +struct phy_device *can_phy_register(struct device_node *mac_node) +{ + struct can_mdio_bus *fmb = &platform_fmb; + struct device_node *np; + struct phy_device *phy; + int phy_addr; + int ret; + + if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED) + return ERR_PTR(-EPROBE_DEFER); + + /* New binding */ + np = of_get_child_by_name(mac_node, "can-transceiver"); + if (!np) + return ERR_PTR(-ENODEV); + + /* Get the next available PHY address, up to PHY_MAX_ADDR */ + phy_addr = ida_simple_get(&phy_can_ida, 0, PHY_MAX_ADDR, GFP_KERNEL); + if (phy_addr < 0) { + err = ERR_PTR(phy_addr); + goto err_of_node_put; + } + + ret = can_phy_add(phy_addr); + if (ret < 0) + goto err_ida_simple_remove; + + phy = phy_device_create(fmb->mii_bus, phy_addr, 0, false, NULL); + if (IS_ERR(phy)) { + ret = ERR_PTR(phy); + goto err_can_phy_del; + } + + of_node_get(np); + phy->mdio.dev.of_node = np; + phy->is_pseudo_fixed_link = true; + + phy_advertise_supported(phy); + + ret = phy_device_register(phy); + if (ret) + goto err_phy_device_free; + + return phy; + +err_phy_device_free: + phy_device_free(phy); +err_can_phy_del: + can_phy_del(phy_addr); +err_ida_simple_remove: + ida_simple_remove(&phy_can_ida, phy_addr); +err_of_node_put: + of_node_put(np); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(can_phy_register); + +void can_phy_unregister(struct phy_device *phy) +{ + phy_device_remove(phy); + of_node_put(phy->mdio.dev.of_node); + can_phy_del(phy->mdio.addr); +} +EXPORT_SYMBOL_GPL(can_phy_unregister); + +static int __init can_mdio_bus_init(void) +{ + struct can_mdio_bus *fmb = &platform_fmb; + int ret; + + pdev = platform_device_register_simple("Virtual CAN PHY Bus", 0, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + fmb->mii_bus = mdiobus_alloc(); + if (fmb->mii_bus == NULL) { + ret = -ENOMEM; + goto err_mdiobus_reg; + } + + snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "virtual-can-0"); + fmb->mii_bus->name = "Virtual CAN PHY Bus"; + fmb->mii_bus->priv = fmb; + fmb->mii_bus->parent = &pdev->dev; + fmb->mii_bus->read = &can_mdio_read; + fmb->mii_bus->write = &can_mdio_write; + /* do not scan the bus for PHYs */ + fmb->mii_bus->phy_mask = ~0; + + ret = mdiobus_register(fmb->mii_bus); + if (ret) + goto err_mdiobus_alloc; + + return 0; + +err_mdiobus_alloc: + mdiobus_free(fmb->mii_bus); +err_mdiobus_reg: + platform_device_unregister(pdev); + return ret; +} +module_init(can_mdio_bus_init); + +static void __exit can_mdio_bus_exit(void) +{ + struct can_mdio_bus *fmb = &platform_fmb; + struct can_phy *fp, *tmp; + + mdiobus_unregister(fmb->mii_bus); + mdiobus_free(fmb->mii_bus); + platform_device_unregister(pdev); + + list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { + list_del(&fp->node); + kfree(fp); + } + ida_destroy(&phy_can_ida); +} +module_exit(can_mdio_bus_exit); + +MODULE_DESCRIPTION("Virtual CAN PHY Bus"); +MODULE_AUTHOR("Oleksij Rempel"); +MODULE_LICENSE("GPLv2"); diff --git a/include/linux/can/phy.h b/include/linux/can/phy.h new file mode 100644 index 000000000000..3772132d9100 --- /dev/null +++ b/include/linux/can/phy.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __CAN_PHY_H +#define __CAN_PHY_H + +#include + +#if IS_ENABLED(CONFIG_CAN_PHY) +extern void can_phy_unregister(struct phy_device *phydev); +struct phy_device *can_phy_register(struct device_node *mac_node); +#else +static inline struct phy_device *can_phy_register(struct device_node *mac_node) +{ + return ERR_PTR(-ENODEV); +} + +static inline void can_phy_unregister(struct phy_device *phydev) +{ +} +#endif /* CONFIG_CAN_PHY */ + +#endif /* __CAN_PHY_H */ From patchwork Fri Oct 23 10:56:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 298644 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D7F6C388F9 for ; Fri, 23 Oct 2020 10:57:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4511D20FC3 for ; Fri, 23 Oct 2020 10:57:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S462630AbgJWK5A (ORCPT ); Fri, 23 Oct 2020 06:57:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52862 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S462575AbgJWK4k (ORCPT ); Fri, 23 Oct 2020 06:56:40 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4F37C0613CE for ; Fri, 23 Oct 2020 03:56:39 -0700 (PDT) Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVukG-00087o-Kr; Fri, 23 Oct 2020 12:56:28 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1kVukF-0001kK-E8; Fri, 23 Oct 2020 12:56:27 +0200 From: Oleksij Rempel To: Andrew Lunn , "David S. Miller" , Florian Fainelli , Heiner Kallweit , Jakub Kicinski , Oliver Hartkopp Cc: Oleksij Rempel , David Jander , kernel@pengutronix.de, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Russell King , mkl@pengutronix.de, Marek Vasut , linux-can@vger.kernel.org Subject: [RFC PATCH v1 2/6] net: phy: add a driver for generic CAN PHYs Date: Fri, 23 Oct 2020 12:56:22 +0200 Message-Id: <20201023105626.6534-3-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201023105626.6534-1-o.rempel@pengutronix.de> References: <20201023105626.6534-1-o.rempel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Generic CAN PHY driver should provide support for simple CAN PHYs (transceiver). Signed-off-by: Oleksij Rempel --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/can_phy_drv.c | 236 ++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 drivers/net/phy/can_phy_drv.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 39e3f57ea60a..c4ae29c8e9ff 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -153,6 +153,12 @@ config BCM_CYGNUS_PHY config BCM_NET_PHYLIB tristate +config CAN_GENERIC_PHY + tristate "Generic CAN PHY" + depends on CAN_PHY_BUS + help + Enable this driver to support the majority of simple CAN PHYs. + config CAN_PHY_BUS tristate "Virtual CAN PHY Bus" depends on PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 0d76d802c07f..80053cb13dc0 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o +obj-$(CONFIG_CAN_GENERIC_PHY) += can_phy_drv.o obj-$(CONFIG_CAN_PHY_BUS) += can_phy_bus.o obj-$(CONFIG_CICADA_PHY) += cicada.o obj-$(CONFIG_CORTINA_PHY) += cortina.o diff --git a/drivers/net/phy/can_phy_drv.c b/drivers/net/phy/can_phy_drv.c new file mode 100644 index 000000000000..c52bf11fdc03 --- /dev/null +++ b/drivers/net/phy/can_phy_drv.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2020 Oleksij Rempel , Pengutronix + +#include +#include +#include +#include + +/* flags */ +#define CAN_GEN_SIC_XL BIT(5) +#define CAN_GEN_SIC BIT(4) +#define CAN_GEN_FD BIT(3) +#define CAN_GEN_HS BIT(2) +#define CAN_GEN_LS BIT(1) +#define CAN_GEN_SW BIT(0) + +struct can_gen_dcfg { + u32 flags; + u32 max_bitrate; +}; + +struct can_gen_priv { + struct regulator *reg_xceiver; + struct can_gen_dcfg dcfg; + bool off; +}; + +static const struct can_gen_dcfg can_gen_nxp_tja1051 = { + .flags = CAN_GEN_HS | CAN_GEN_FD, + .max_bitrate = 5000000, +}; + +static const struct of_device_id can_gen_ids[] = { + { + .compatible = "can,generic-transceiver", + }, { + .compatible = "nxp,tja1051", + .data = &can_gen_nxp_tja1051, + }, { /* sentinel */ } +}; + +static void can_gen_get_bitrate(struct can_gen_priv *priv, + struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + struct can_gen_dcfg *dcfg = &priv->dcfg; + u32 max_bitrate; + int ret; + + ret = of_property_read_u32(np, "max-bitrate", &max_bitrate); + if (ret) + phydev_warn(phydev, "Can't read max-bitrate\n"); + + if (!dcfg->max_bitrate && !max_bitrate) { + phydev_warn(phydev, "Huh... Limitless PHY!!\n"); + + if (dcfg->flags & CAN_GEN_FD) { + max_bitrate = 12000000; /* 12Mbit */ + } else if (dcfg->flags & CAN_GEN_HS) { + max_bitrate = 1000000; /* 1Mbit */ + } else if (dcfg->flags & CAN_GEN_LS) { + max_bitrate = 125000; /* 125Kbit */ + } else if (dcfg->flags & CAN_GEN_SW) { + max_bitrate = 83300; /* 83.3kbit */ + } else { + max_bitrate = 12000000; /* 12Mbit */ + phydev_warn(phydev, "Can't determine the max bitrate! Set: %d\n", + max_bitrate); + } + + dcfg->max_bitrate = max_bitrate; + } else if (dcfg->max_bitrate && max_bitrate > dcfg->max_bitrate) { + phydev_info(phydev, "Ignoring max-bitrate property: %d, hw limit: %d\n", + max_bitrate, dcfg->max_bitrate); + } else { + dcfg->max_bitrate = max_bitrate; + } +} + +static void can_gen_parse_dt_flags(struct can_gen_priv *priv, + struct phy_device *phydev) +{ + struct can_gen_dcfg *dcfg = &priv->dcfg; + struct device *dev = &phydev->mdio.dev; + + if (device_property_read_bool(dev, "can-sic-xl")) + dcfg->flags |= CAN_GEN_SIC_XL; + if (device_property_read_bool(dev, "can-sic")) + dcfg->flags |= CAN_GEN_SIC; + if (device_property_read_bool(dev, "can-fd")) + dcfg->flags |= CAN_GEN_FD; + if (device_property_read_bool(dev, "can-hs")) + dcfg->flags |= CAN_GEN_HS; + if (device_property_read_bool(dev, "can-ls")) + dcfg->flags |= CAN_GEN_LS; + if (device_property_read_bool(dev, "can-sw")) + dcfg->flags |= CAN_GEN_SW; +} + +static int can_gen_probe(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + const struct of_device_id *match; + struct regulator *reg_xceiver; + struct can_gen_priv *priv; + + match = of_match_node(can_gen_ids, np); + if (!match) + return 0; + + reg_xceiver = devm_regulator_get_optional(&phydev->mdio.dev, "xceiver"); + if (PTR_ERR(reg_xceiver) == -ENODEV) + reg_xceiver = NULL; + else if (IS_ERR(reg_xceiver)) + return dev_err_probe(&phydev->mdio.dev, PTR_ERR(reg_xceiver), + "Failed to get Transceiver regulator!\n"); + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (!match->data) + can_gen_parse_dt_flags(priv, phydev); + else + memcpy(&priv->dcfg, match->data, sizeof(priv->dcfg)); + + can_gen_get_bitrate(priv, phydev); + + phydev->priv = priv; + priv->reg_xceiver = reg_xceiver; + priv->off = true; + + return 0; +} + +static int can_gen_read_status(struct phy_device *phydev) +{ + phydev->link = true; + phydev->duplex = DUPLEX_HALF; + + return 0; +} + +static int can_gen_match_phy_device(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + const struct of_device_id *match; + + if (phydev->phy_id) + return 0; + + match = of_match_node(can_gen_ids, np); + if (!match) + return 0; + + return 1; +} + +static int can_get_features(struct phy_device *phydev) +{ + struct can_gen_priv *priv = phydev->priv; + struct can_gen_dcfg *dcfg = &priv->dcfg; + + phydev->interface = PHY_INTERFACE_MODE_CAN; + phydev->max_bitrate = dcfg->max_bitrate; + + if (dcfg->flags & CAN_GEN_SIC_XL) + linkmode_set_bit(ETHTOOL_LINK_MODE_CAN_SIC_XL_BIT, + phydev->supported); + if (dcfg->flags & CAN_GEN_SIC) + linkmode_set_bit(ETHTOOL_LINK_MODE_CAN_SIC_BIT, + phydev->supported); + if (dcfg->flags & CAN_GEN_FD) + linkmode_set_bit(ETHTOOL_LINK_MODE_CAN_FD_BIT, + phydev->supported); + if (dcfg->flags & CAN_GEN_HS) + linkmode_set_bit(ETHTOOL_LINK_MODE_CAN_HS_BIT, + phydev->supported); + if (dcfg->flags & CAN_GEN_LS) + linkmode_set_bit(ETHTOOL_LINK_MODE_CAN_LS_BIT, + phydev->supported); + if (dcfg->flags & CAN_GEN_SW) + linkmode_set_bit(ETHTOOL_LINK_MODE_CAN_SW_BIT, + phydev->supported); + + return 0; +} + +static int can_gen_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int can_gen_resume(struct phy_device *phydev) +{ + struct can_gen_priv *priv = phydev->priv; + + /* Resume can be called multiple times, so it will be asymmetric to + * the suspend call.*/ + if (!priv->off) + return 0; + + priv->off = false; + + return regulator_enable(priv->reg_xceiver); +} + +static int can_gen_suspend(struct phy_device *phydev) +{ + struct can_gen_priv *priv = phydev->priv; + + if (priv->off) + return 0; + + priv->off = true; + + return regulator_disable(priv->reg_xceiver); +} + +static struct phy_driver can_gen_drv[] = { + { + .name = "Generic CAN PHY", + .match_phy_device = can_gen_match_phy_device, + .probe = can_gen_probe, + .read_status = can_gen_read_status, + .suspend = can_gen_suspend, + .resume = can_gen_resume, + .get_features = can_get_features, + .config_aneg = can_gen_config_aneg, + }, +}; +module_phy_driver(can_gen_drv); + +MODULE_DESCRIPTION("Generic CAN PHY driver"); +MODULE_AUTHOR("Oleksij Rempel"); +MODULE_LICENSE("GPLv2"); From patchwork Fri Oct 23 10:56:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 288150 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EBA5AC55179 for ; Fri, 23 Oct 2020 10:57:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A231E21D43 for ; Fri, 23 Oct 2020 10:57:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S462528AbgJWK5E (ORCPT ); Fri, 23 Oct 2020 06:57:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52864 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S462576AbgJWK4k (ORCPT ); Fri, 23 Oct 2020 06:56:40 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CB106C0613D2 for ; Fri, 23 Oct 2020 03:56:39 -0700 (PDT) Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVukG-00087p-Kr; Fri, 23 Oct 2020 12:56:28 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1kVukF-0001kT-F6; Fri, 23 Oct 2020 12:56:27 +0200 From: Oleksij Rempel To: Andrew Lunn , "David S. Miller" , Florian Fainelli , Heiner Kallweit , Jakub Kicinski , Oliver Hartkopp Cc: Oleksij Rempel , David Jander , kernel@pengutronix.de, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Russell King , mkl@pengutronix.de, Marek Vasut , linux-can@vger.kernel.org Subject: [RFC PATCH v1 3/6] net: phy: add CAN interface mode Date: Fri, 23 Oct 2020 12:56:23 +0200 Message-Id: <20201023105626.6534-4-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201023105626.6534-1-o.rempel@pengutronix.de> References: <20201023105626.6534-1-o.rempel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Signed-off-by: Oleksij Rempel --- drivers/net/phy/phy.c | 2 ++ include/linux/phy.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 35525a671400..4fb355df3e61 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -324,6 +324,8 @@ void phy_ethtool_ksettings_get(struct phy_device *phydev, cmd->base.master_slave_state = phydev->master_slave_state; if (phydev->interface == PHY_INTERFACE_MODE_MOCA) cmd->base.port = PORT_BNC; + else if (phydev->interface == PHY_INTERFACE_MODE_CAN) + cmd->base.port = PORT_OTHER; else cmd->base.port = PORT_MII; cmd->base.transceiver = phy_is_internal(phydev) ? diff --git a/include/linux/phy.h b/include/linux/phy.h index 92225fc0d105..c5d8628cecf3 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -144,6 +144,7 @@ typedef enum { PHY_INTERFACE_MODE_USXGMII, /* 10GBASE-KR - with Clause 73 AN */ PHY_INTERFACE_MODE_10GKR, + PHY_INTERFACE_MODE_CAN, PHY_INTERFACE_MODE_MAX, } phy_interface_t; @@ -225,6 +226,8 @@ static inline const char *phy_modes(phy_interface_t interface) return "usxgmii"; case PHY_INTERFACE_MODE_10GKR: return "10gbase-kr"; + case PHY_INTERFACE_MODE_CAN: + return "can"; default: return "unknown"; } From patchwork Fri Oct 23 10:56:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 298643 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B76EBC55178 for ; Fri, 23 Oct 2020 10:57:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 70EB620FC3 for ; Fri, 23 Oct 2020 10:57:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S462658AbgJWK5R (ORCPT ); Fri, 23 Oct 2020 06:57:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S462555AbgJWK4i (ORCPT ); Fri, 23 Oct 2020 06:56:38 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B2FEC0613D4 for ; Fri, 23 Oct 2020 03:56:38 -0700 (PDT) Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVukG-00087q-Kr; Fri, 23 Oct 2020 12:56:28 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1kVukF-0001kc-G7; Fri, 23 Oct 2020 12:56:27 +0200 From: Oleksij Rempel To: Andrew Lunn , "David S. Miller" , Florian Fainelli , Heiner Kallweit , Jakub Kicinski , Oliver Hartkopp Cc: Oleksij Rempel , David Jander , kernel@pengutronix.de, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Russell King , mkl@pengutronix.de, Marek Vasut , linux-can@vger.kernel.org Subject: [RFC PATCH v1 4/6] net: add CAN specific link modes Date: Fri, 23 Oct 2020 12:56:24 +0200 Message-Id: <20201023105626.6534-5-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201023105626.6534-1-o.rempel@pengutronix.de> References: <20201023105626.6534-1-o.rempel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds the CAN specific link modes to the ethtool user space API. Signed-off-by: Oleksij Rempel --- drivers/net/phy/phy-core.c | 2 +- include/uapi/linux/ethtool.h | 9 +++++++++ net/ethtool/common.c | 7 +++++++ net/ethtool/linkmodes.c | 7 +++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 635be83962b6..0f0c136890e0 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -13,7 +13,7 @@ */ const char *phy_speed_to_str(int speed) { - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 92, + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 98, "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " "If a speed or mode has been added please update phy_speed_to_str " "and the PHY settings array.\n"); diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 9ca87bc73c44..eb3cb846c0a6 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1619,6 +1619,15 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89, ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, + + /* CAN specific capabilities */ + ETHTOOL_LINK_MODE_CAN_SW_BIT = 92, + ETHTOOL_LINK_MODE_CAN_LS_BIT = 93, + ETHTOOL_LINK_MODE_CAN_HS_BIT = 94, + ETHTOOL_LINK_MODE_CAN_FD_BIT = 95, + ETHTOOL_LINK_MODE_CAN_SIC_BIT = 96, + ETHTOOL_LINK_MODE_CAN_SIC_XL_BIT = 97, + /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS }; diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 24036e3055a1..3d2fa29291a1 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -194,6 +194,13 @@ const char link_mode_names[][ETH_GSTRING_LEN] = { __DEFINE_LINK_MODE_NAME(400000, CR4, Full), __DEFINE_LINK_MODE_NAME(100, FX, Half), __DEFINE_LINK_MODE_NAME(100, FX, Full), + + __DEFINE_SPECIAL_MODE_NAME(CAN_SW, "Single-wire CAN"), /* SAE J2411 */ + __DEFINE_SPECIAL_MODE_NAME(CAN_LS, "CAN low-speed"), /* ISO 11898-3 (aka. Fault tolerant) */ + __DEFINE_SPECIAL_MODE_NAME(CAN_HS, "CAN high-speed"), /* ISO 11898-2:2016 limited to bit-rates of 1 Mbit/s */ + __DEFINE_SPECIAL_MODE_NAME(CAN_FD, "CAN FD"), /* ISO 11898-2:2016 supporting improved optional parameters */ + __DEFINE_SPECIAL_MODE_NAME(CAN_SIC, "CAN SIC"), /* CiA 601-4 */ + __DEFINE_SPECIAL_MODE_NAME(CAN_SIC_XL, "CAN SIC XL"), /* CiA 610-3 */ }; static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS); diff --git a/net/ethtool/linkmodes.c b/net/ethtool/linkmodes.c index c5bcb9abc8b9..eae0f75681fe 100644 --- a/net/ethtool/linkmodes.c +++ b/net/ethtool/linkmodes.c @@ -264,6 +264,13 @@ static const struct link_mode_info link_mode_params[] = { __DEFINE_LINK_MODE_PARAMS(400000, CR4, Full), __DEFINE_LINK_MODE_PARAMS(100, FX, Half), __DEFINE_LINK_MODE_PARAMS(100, FX, Full), + + __DEFINE_SPECIAL_MODE_PARAMS(CAN_SW), + __DEFINE_SPECIAL_MODE_PARAMS(CAN_LS), + __DEFINE_SPECIAL_MODE_PARAMS(CAN_HS), + __DEFINE_SPECIAL_MODE_PARAMS(CAN_FD), + __DEFINE_SPECIAL_MODE_PARAMS(CAN_SIC), + __DEFINE_SPECIAL_MODE_PARAMS(CAN_SIC_XL), }; const struct nla_policy ethnl_linkmodes_set_policy[] = { From patchwork Fri Oct 23 10:56:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 288149 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 31276C56201 for ; Fri, 23 Oct 2020 10:57:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D5E9021D43 for ; Fri, 23 Oct 2020 10:57:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S462565AbgJWK4j (ORCPT ); Fri, 23 Oct 2020 06:56:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S462552AbgJWK4i (ORCPT ); Fri, 23 Oct 2020 06:56:38 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F4218C0613D2 for ; Fri, 23 Oct 2020 03:56:37 -0700 (PDT) Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVukG-00087r-Kr; Fri, 23 Oct 2020 12:56:28 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1kVukF-0001km-H8; Fri, 23 Oct 2020 12:56:27 +0200 From: Oleksij Rempel To: Andrew Lunn , "David S. Miller" , Florian Fainelli , Heiner Kallweit , Jakub Kicinski , Oliver Hartkopp Cc: Oleksij Rempel , David Jander , kernel@pengutronix.de, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Russell King , mkl@pengutronix.de, Marek Vasut , linux-can@vger.kernel.org Subject: [RFC PATCH v1 5/6] can: flexcan: add phylink support Date: Fri, 23 Oct 2020 12:56:25 +0200 Message-Id: <20201023105626.6534-6-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201023105626.6534-1-o.rempel@pengutronix.de> References: <20201023105626.6534-1-o.rempel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Signed-off-by: Oleksij Rempel --- drivers/net/can/Kconfig | 2 + drivers/net/can/flexcan.c | 133 +++++++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 424970939fd4..fc5db96a34be 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -98,6 +98,8 @@ config CAN_AT91 config CAN_FLEXCAN tristate "Support for Freescale FLEXCAN based chips" depends on OF && HAS_IOMEM + select PHYLINK + select CAN_PHY help Say Y here if you want to support for Freescale FlexCAN. diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 881799bd9c5e..c320eed31322 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -361,6 +365,10 @@ struct flexcan_priv { /* Read and Write APIs */ u32 (*read)(void __iomem *addr); void (*write)(u32 val, void __iomem *addr); + + phy_interface_t phy_if_mode; + struct phylink *phylink; + struct phylink_config phylink_config; }; static const struct flexcan_devtype_data fsl_p1010_devtype_data = { @@ -1653,9 +1661,16 @@ static int flexcan_open(struct net_device *dev) return -EINVAL; } + err = phylink_of_phy_connect(priv->phylink, priv->dev->of_node, 0); + if (err) { + netdev_err(dev, "phylink_of_phy_connect filed with err: %i\n", + err); + return err; + } + err = pm_runtime_get_sync(priv->dev); if (err < 0) - return err; + goto out_phy_put; err = open_candev(dev); if (err) @@ -1710,6 +1725,8 @@ static int flexcan_open(struct net_device *dev) can_rx_offload_enable(&priv->offload); netif_start_queue(dev); + phylink_start(priv->phylink); + return 0; out_offload_del: @@ -1720,6 +1737,8 @@ static int flexcan_open(struct net_device *dev) close_candev(dev); out_runtime_put: pm_runtime_put(priv->dev); + out_phy_put: + phylink_disconnect_phy(priv->phylink); return err; } @@ -1740,6 +1759,104 @@ static int flexcan_close(struct net_device *dev) can_led_event(dev, CAN_LED_EVENT_STOP); + phylink_stop(priv->phylink); + phylink_disconnect_phy(priv->phylink); + + return 0; +} + +static void flexcan_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ + /* Not Supported */ +} + +static void flexcan_mac_validate(struct phylink_config *config, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct flexcan_priv *priv = netdev_priv(to_net_dev(config->dev)); + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + switch (state->interface) { + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_CAN: + break; + default: + goto unsupported; + } + + phylink_set(mask, CAN_HS); + phylink_set(mask, CAN_LS); + phylink_set(mask, CAN_SW); + + /* max bitrate supported by the controller */ + if (!state->max_bitrate || state->max_bitrate > 1000000) + state->max_bitrate = 1000000; + + priv->can.bitrate_max = state->max_bitrate; + + bitmap_and(supported, supported, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + + return; +unsupported: + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static void flexcan_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) +{ + state->link = 0; +} + +static void flexcan_mac_an_restart(struct phylink_config *config) +{ + /* Not Supported */ +} + +static void flexcan_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ + /* Not Supported */ +} + +static void flexcan_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + /* Not Supported */ +} + + + +static const struct phylink_mac_ops flexcan_phylink_mac_ops = { + .validate = flexcan_mac_validate, + .mac_pcs_get_state = flexcan_mac_pcs_get_state, + .mac_an_restart = flexcan_mac_an_restart, + .mac_config = flexcan_mac_config, + .mac_link_down = flexcan_mac_link_down, + .mac_link_up = flexcan_mac_link_up, +}; + +static int flexcan_phylink_setup(struct flexcan_priv *priv, + struct net_device *dev) +{ + struct phylink *phylink; + + priv->phylink_config.dev = &dev->dev; + priv->phylink_config.type = PHYLINK_NETDEV; + + phylink = phylink_create(&priv->phylink_config, priv->dev->fwnode, + priv->phy_if_mode, &flexcan_phylink_mac_ops); + if (IS_ERR(phylink)) + return PTR_ERR(phylink); + + priv->phylink = phylink; return 0; } @@ -1818,6 +1935,12 @@ static int register_flexcandev(struct net_device *dev) if (err) goto out_chip_disable; + err = flexcan_phylink_setup(priv, dev); + if (err) { + netdev_err(dev, "failed to setup phylink (%d)\n", err); + goto out_chip_disable; + } + /* Disable core and let pm_runtime_put() disable the clocks. * If CONFIG_PM is not enabled, the clocks will stay powered. */ @@ -1921,6 +2044,7 @@ static int flexcan_probe(struct platform_device *pdev) { const struct of_device_id *of_id; const struct flexcan_devtype_data *devtype_data; + phy_interface_t phy_if_mode; struct net_device *dev; struct flexcan_priv *priv; struct regulator *reg_xceiver; @@ -1943,6 +2067,12 @@ static int flexcan_probe(struct platform_device *pdev) "clock-frequency", &clock_freq); of_property_read_u8(pdev->dev.of_node, "fsl,clk-source", &clk_src); + can_phy_register(pdev->dev.of_node); + err = of_get_phy_mode(pdev->dev.of_node, &phy_if_mode); + if (err) { + dev_err(&pdev->dev, "missing phy-mode property in DT\n"); + return err; + } } if (!clock_freq) { @@ -2019,6 +2149,7 @@ static int flexcan_probe(struct platform_device *pdev) priv->clk_src = clk_src; priv->devtype_data = devtype_data; priv->reg_xceiver = reg_xceiver; + priv->phy_if_mode = phy_if_mode; if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) { priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | From patchwork Fri Oct 23 10:56:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 298646 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73E27C55178 for ; Fri, 23 Oct 2020 10:56:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0D9B721D43 for ; Fri, 23 Oct 2020 10:56:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S462591AbgJWK4l (ORCPT ); Fri, 23 Oct 2020 06:56:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52868 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S462568AbgJWK4k (ORCPT ); Fri, 23 Oct 2020 06:56:40 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B86FC0613D5 for ; Fri, 23 Oct 2020 03:56:40 -0700 (PDT) Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVukG-00087s-Kr; Fri, 23 Oct 2020 12:56:28 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1kVukF-0001kw-I7; Fri, 23 Oct 2020 12:56:27 +0200 From: Oleksij Rempel To: Andrew Lunn , "David S. Miller" , Florian Fainelli , Heiner Kallweit , Jakub Kicinski , Oliver Hartkopp Cc: Oleksij Rempel , David Jander , kernel@pengutronix.de, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Russell King , mkl@pengutronix.de, Marek Vasut , linux-can@vger.kernel.org Subject: [RFC PATCH v1 6/6] can: flexcan: add ethtool support Date: Fri, 23 Oct 2020 12:56:26 +0200 Message-Id: <20201023105626.6534-7-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201023105626.6534-1-o.rempel@pengutronix.de> References: <20201023105626.6534-1-o.rempel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Signed-off-by: Oleksij Rempel --- drivers/net/can/flexcan.c | 111 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index c320eed31322..8f487ac37f5e 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -247,6 +247,11 @@ /* support memory detection and correction */ #define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10) +#define FLEXCAN_DEFAULT_MSG_ENABLE \ + (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_TIMER \ + NETIF_MSG_IFDOWN | NETIF_MSG_IFUP | NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + /* Structure of the message buffer */ struct flexcan_mb { u32 can_ctrl; @@ -369,6 +374,18 @@ struct flexcan_priv { phy_interface_t phy_if_mode; struct phylink *phylink; struct phylink_config phylink_config; + u32 msg_enable; +}; + +struct flexcan_statistic { + unsigned short offset; + u32 mask; + const char name[ETH_GSTRING_LEN]; +}; + +static const struct flexcan_statistic flexcan_statistics[] = { + { 0x001c, GENMASK(15, 7), "RX_ERR", }, + { 0x001c, GENMASK(7, 0), "TX_ERR", }, }; static const struct flexcan_devtype_data fsl_p1010_devtype_data = { @@ -492,6 +509,98 @@ static inline void flexcan_write_le(u32 val, void __iomem *addr) iowrite32(val, addr); } +static void flexcan_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + + strlcpy(info->driver, "flexcan", sizeof(info->driver)); + strlcpy(info->bus_info, of_node_full_name(priv->dev->of_node), + sizeof(info->bus_info)); +} + +static int flexcan_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *kset) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + + return phylink_ethtool_ksettings_get(priv->phylink, kset); +} + +static int flexcan_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *kset) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + + return phylink_ethtool_ksettings_set(priv->phylink, kset); +} + +static int flexcan_ethtool_nway_reset(struct net_device *ndev) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + + return phylink_ethtool_nway_reset(priv->phylink); +} + +static void flexcan_set_msglevel(struct net_device *ndev, u32 value) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + + priv->msg_enable = value; +} + +static u32 flexcan_get_msglevel(struct net_device *ndev) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + + return priv->msg_enable; +} + +static void flexcan_ethtool_get_strings(struct net_device *netdev, u32 sset, + u8 *data) +{ + if (sset == ETH_SS_STATS) { + int i; + + for (i = 0; i < ARRAY_SIZE(flexcan_statistics); i++) + memcpy(data + i * ETH_GSTRING_LEN, + flexcan_statistics[i].name, ETH_GSTRING_LEN); + } +} + +static void flexcan_ethtool_get_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct flexcan_priv *priv = netdev_priv(ndev); + struct flexcan_regs __iomem *regs = priv->regs; + int i; + + for (i = 0; i < ARRAY_SIZE(flexcan_statistics); i++) + *data++ = u32_get_bits(priv->read(regs + flexcan_statistics[i].offset), + flexcan_statistics[i].mask); +} + +static int flexcan_ethtool_get_sset_count(struct net_device *ndev, int sset) +{ + if (sset == ETH_SS_STATS) + return ARRAY_SIZE(flexcan_statistics); + return -EOPNOTSUPP; +} + +static const struct ethtool_ops flexcan_ethtool_ops = { + .get_drvinfo = flexcan_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, + .get_link_ksettings = flexcan_get_link_ksettings, + .set_link_ksettings = flexcan_set_link_ksettings, + .nway_reset = flexcan_ethtool_nway_reset, + .get_msglevel = flexcan_get_msglevel, + .set_msglevel = flexcan_set_msglevel, + .get_strings = flexcan_ethtool_get_strings, + .get_ethtool_stats = flexcan_ethtool_get_stats, + .get_sset_count = flexcan_ethtool_get_sset_count, +}; + static struct flexcan_mb __iomem *flexcan_get_mb(const struct flexcan_priv *priv, u8 mb_index) { @@ -2122,6 +2231,7 @@ static int flexcan_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); dev->netdev_ops = &flexcan_netdev_ops; + dev->ethtool_ops = &flexcan_ethtool_ops; dev->irq = irq; dev->flags |= IFF_ECHO; @@ -2150,6 +2260,7 @@ static int flexcan_probe(struct platform_device *pdev) priv->devtype_data = devtype_data; priv->reg_xceiver = reg_xceiver; priv->phy_if_mode = phy_if_mode; + priv->msg_enable = netif_msg_init(-1, FLEXCAN_DEFAULT_MSG_ENABLE); if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) { priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD |