linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v1 0/6] add initial CAN PHY support
@ 2020-10-23 10:56 Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Oleksij Rempel
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

This patch set is introducing PHY support for CAN.

Why it is needed?
- A usual CAN PHY has an enable or silent mode pin. This pin needs to be
  pulled into the correct direction, so that the CAN controller can
  access the CAN network. So far this has been "hacked" into the
  CAN controller driver, by enabling/disabling regulators. Better use
  proper PHY drivers instead.
- Bit rate limits. There are different types of CAN PHYs not all support
  all bit rates. Further the upper limit of CAN FD PHYs is not given by
  the standard by by the PHY itself. Use the PHY link framework to
  validate bit rate limits.
- The upcoming CAN SIC and CAN SIC XL PHYs use a different interface to
  the CAN controller. This means the controller needs to know which type
  of PHY is attached to configure the interface in the correct mode. Use
  PHY link for that, too.
- Another topic is cable testing/diagnostics. Unfortunately this is not
  standardized in CAN, but there are several boards that implement CAN
  cable testing in some way or another. Use PHY framework as an
  abstraction.
- The class of CAN low-speed PHYs has enhanced error detection
  capabilities, compared to normal (CAN high-speed and CAN FD) PHYs.
  Use PHY framework to implement CAN low-speed PHY drivers.

Oleksij Rempel (6):
  net: phy: add CAN PHY Virtual Bus
  net: phy: add a driver for generic CAN PHYs
  net: phy: add CAN interface mode
  net: add CAN specific link modes
  can: flexcan: add phylink support
  can: flexcan: add ethtool support

 drivers/net/can/Kconfig       |   2 +
 drivers/net/can/flexcan.c     | 244 +++++++++++++++++++++++++++++++++-
 drivers/net/phy/Kconfig       |  14 ++
 drivers/net/phy/Makefile      |   2 +
 drivers/net/phy/can_phy_bus.c | 196 +++++++++++++++++++++++++++
 drivers/net/phy/can_phy_drv.c | 236 ++++++++++++++++++++++++++++++++
 drivers/net/phy/phy-core.c    |   2 +-
 drivers/net/phy/phy.c         |   2 +
 include/linux/can/phy.h       |  21 +++
 include/linux/phy.h           |   3 +
 include/uapi/linux/ethtool.h  |   9 ++
 net/ethtool/common.c          |   7 +
 net/ethtool/linkmodes.c       |   7 +
 13 files changed, 743 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/phy/can_phy_bus.c
 create mode 100644 drivers/net/phy/can_phy_drv.c
 create mode 100644 include/linux/can/phy.h

-- 
2.28.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
@ 2020-10-23 10:56 ` Oleksij Rempel
  2020-10-23 20:18   ` Andrew Lunn
  2020-10-23 20:53   ` Andrew Lunn
  2020-10-23 10:56 ` [RFC PATCH v1 2/6] net: phy: add a driver for generic CAN PHYs Oleksij Rempel
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

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 <o.rempel@pengutronix.de>
---
 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 <kernel@pengutronix.de>, Pengutronix
+
+#include <linux/can/phy.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+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 <linux/phy.h>
+
+#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 */
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH v1 2/6] net: phy: add a driver for generic CAN PHYs
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Oleksij Rempel
@ 2020-10-23 10:56 ` Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 3/6] net: phy: add CAN interface mode Oleksij Rempel
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

Generic CAN PHY driver should provide support for simple CAN PHYs
(transceiver).

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 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 <kernel@pengutronix.de>, Pengutronix
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/regulator/consumer.h>
+
+/* 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");
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH v1 3/6] net: phy: add CAN interface mode
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 2/6] net: phy: add a driver for generic CAN PHYs Oleksij Rempel
@ 2020-10-23 10:56 ` Oleksij Rempel
  2020-10-23 20:24   ` Andrew Lunn
  2020-10-23 10:56 ` [RFC PATCH v1 4/6] net: add CAN specific link modes Oleksij Rempel
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 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";
 	}
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH v1 4/6] net: add CAN specific link modes
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
                   ` (2 preceding siblings ...)
  2020-10-23 10:56 ` [RFC PATCH v1 3/6] net: phy: add CAN interface mode Oleksij Rempel
@ 2020-10-23 10:56 ` Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 5/6] can: flexcan: add phylink support Oleksij Rempel
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

This patch adds the CAN specific link modes to the ethtool user space
API.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 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[] = {
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH v1 5/6] can: flexcan: add phylink support
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
                   ` (3 preceding siblings ...)
  2020-10-23 10:56 ` [RFC PATCH v1 4/6] net: add CAN specific link modes Oleksij Rempel
@ 2020-10-23 10:56 ` Oleksij Rempel
  2020-10-23 10:56 ` [RFC PATCH v1 6/6] can: flexcan: add ethtool support Oleksij Rempel
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 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 <linux/can/dev.h>
 #include <linux/can/error.h>
 #include <linux/can/led.h>
+#include <linux/can/phy.h>
 #include <linux/can/rx-offload.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -24,6 +25,9 @@
 #include <linux/netdevice.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/phylink.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -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 |
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH v1 6/6] can: flexcan: add ethtool support
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
                   ` (4 preceding siblings ...)
  2020-10-23 10:56 ` [RFC PATCH v1 5/6] can: flexcan: add phylink support Oleksij Rempel
@ 2020-10-23 10:56 ` Oleksij Rempel
  2020-10-23 11:45 ` [RFC PATCH v1 0/6] add initial CAN PHY support Russell King - ARM Linux admin
  2020-10-23 20:30 ` Andrew Lunn
  7 siblings, 0 replies; 15+ messages in thread
From: Oleksij Rempel @ 2020-10-23 10:56 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp
  Cc: Oleksij Rempel, David Jander, kernel, linux-kernel, netdev,
	Russell King, mkl, Marek Vasut, linux-can

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 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 |
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 0/6] add initial CAN PHY support
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
                   ` (5 preceding siblings ...)
  2020-10-23 10:56 ` [RFC PATCH v1 6/6] can: flexcan: add ethtool support Oleksij Rempel
@ 2020-10-23 11:45 ` Russell King - ARM Linux admin
  2020-10-23 12:14   ` Marc Kleine-Budde
  2020-10-23 20:30 ` Andrew Lunn
  7 siblings, 1 reply; 15+ messages in thread
From: Russell King - ARM Linux admin @ 2020-10-23 11:45 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Andrew Lunn, David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp, David Jander, kernel,
	linux-kernel, netdev, mkl, Marek Vasut, linux-can

On Fri, Oct 23, 2020 at 12:56:20PM +0200, Oleksij Rempel wrote:
> - The upcoming CAN SIC and CAN SIC XL PHYs use a different interface to
>   the CAN controller. This means the controller needs to know which type
>   of PHY is attached to configure the interface in the correct mode. Use
>   PHY link for that, too.

Is this dynamic in some form?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 0/6] add initial CAN PHY support
  2020-10-23 11:45 ` [RFC PATCH v1 0/6] add initial CAN PHY support Russell King - ARM Linux admin
@ 2020-10-23 12:14   ` Marc Kleine-Budde
  2020-10-23 12:22     ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 15+ messages in thread
From: Marc Kleine-Budde @ 2020-10-23 12:14 UTC (permalink / raw)
  To: Russell King - ARM Linux admin, Oleksij Rempel
  Cc: Marek Vasut, Andrew Lunn, Florian Fainelli, Oliver Hartkopp,
	linux-kernel, linux-can, netdev, kernel, David Jander,
	Jakub Kicinski, David S. Miller, Heiner Kallweit


[-- Attachment #1.1: Type: text/plain, Size: 1200 bytes --]

On 10/23/20 1:45 PM, Russell King - ARM Linux admin wrote:
> On Fri, Oct 23, 2020 at 12:56:20PM +0200, Oleksij Rempel wrote:
>> - The upcoming CAN SIC and CAN SIC XL PHYs use a different interface to
>>   the CAN controller. This means the controller needs to know which type
>>   of PHY is attached to configure the interface in the correct mode. Use
>>   PHY link for that, too.
> 
> Is this dynamic in some form?

There isn't any CAN SIC transceivers out there yet. I suspect there will be no
auto detection possible, so we would describe the type of the attached
transceiver via device tree.

In the future I can think of some devices that have a MUX and use the a classic
transceiver (CAN high-speed) for legacy deployments and CAN SIC transceivers if
connected to a "modern" CAN bus.

Someone (i.e. the user or the system integrator) has to configure the MUX to
select the correct transceiver.

Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde           |
Embedded Linux                   | https://www.pengutronix.de  |
Vertretung West/Dortmund         | Phone: +49-231-2826-924     |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-5555 |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 0/6] add initial CAN PHY support
  2020-10-23 12:14   ` Marc Kleine-Budde
@ 2020-10-23 12:22     ` Russell King - ARM Linux admin
  2020-10-23 13:04       ` Marc Kleine-Budde
  0 siblings, 1 reply; 15+ messages in thread
From: Russell King - ARM Linux admin @ 2020-10-23 12:22 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Oleksij Rempel, Marek Vasut, Andrew Lunn, Florian Fainelli,
	Oliver Hartkopp, linux-kernel, linux-can, netdev, kernel,
	David Jander, Jakub Kicinski, David S. Miller, Heiner Kallweit

On Fri, Oct 23, 2020 at 02:14:09PM +0200, Marc Kleine-Budde wrote:
> On 10/23/20 1:45 PM, Russell King - ARM Linux admin wrote:
> > On Fri, Oct 23, 2020 at 12:56:20PM +0200, Oleksij Rempel wrote:
> >> - The upcoming CAN SIC and CAN SIC XL PHYs use a different interface to
> >>   the CAN controller. This means the controller needs to know which type
> >>   of PHY is attached to configure the interface in the correct mode. Use
> >>   PHY link for that, too.
> > 
> > Is this dynamic in some form?
> 
> There isn't any CAN SIC transceivers out there yet. I suspect there will be no
> auto detection possible, so we would describe the type of the attached
> transceiver via device tree.
> 
> In the future I can think of some devices that have a MUX and use the a classic
> transceiver (CAN high-speed) for legacy deployments and CAN SIC transceivers if
> connected to a "modern" CAN bus.
> 
> Someone (i.e. the user or the system integrator) has to configure the MUX to
> select the correct transceiver.

Hmm. So it's static, and described in firmware. So, that brings me to
the obvious question: why use phylink for this rather than the phylib
APIs?

phylink isn't obsoleting phylib in any way, and phylib does support
the ability for the PHY to change its MAC side interface (if it didn't
then PHYs such as 88x3310 and similar wouldn't be usable.)

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 0/6] add initial CAN PHY support
  2020-10-23 12:22     ` Russell King - ARM Linux admin
@ 2020-10-23 13:04       ` Marc Kleine-Budde
  0 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2020-10-23 13:04 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Oleksij Rempel, Marek Vasut, Andrew Lunn, Florian Fainelli,
	Oliver Hartkopp, linux-kernel, linux-can, netdev, kernel,
	David Jander, Jakub Kicinski, David S. Miller, Heiner Kallweit


[-- Attachment #1.1: Type: text/plain, Size: 2096 bytes --]

On 10/23/20 2:22 PM, Russell King - ARM Linux admin wrote:
> On Fri, Oct 23, 2020 at 02:14:09PM +0200, Marc Kleine-Budde wrote:
>> On 10/23/20 1:45 PM, Russell King - ARM Linux admin wrote:
>>> On Fri, Oct 23, 2020 at 12:56:20PM +0200, Oleksij Rempel wrote:
>>>> - The upcoming CAN SIC and CAN SIC XL PHYs use a different interface to
>>>>   the CAN controller. This means the controller needs to know which type
>>>>   of PHY is attached to configure the interface in the correct mode. Use
>>>>   PHY link for that, too.
>>>
>>> Is this dynamic in some form?
>>
>> There isn't any CAN SIC transceivers out there yet. I suspect there will be no
>> auto detection possible, so we would describe the type of the attached
>> transceiver via device tree.
>>
>> In the future I can think of some devices that have a MUX and use the a classic
>> transceiver (CAN high-speed) for legacy deployments and CAN SIC transceivers if
>> connected to a "modern" CAN bus.
>>
>> Someone (i.e. the user or the system integrator) has to configure the MUX to
>> select the correct transceiver.
> 
> Hmm. So it's static, and described in firmware.

The use case where the system has a MUX (to route the signals to either one or
the other transceiver), the used transceiver would be selected by software.

It's static in that sense, as there is no hotplug of unknown devices, no-one
will swap the CAN-SPF+ module against a CAN-SIC-SFP+ module :)

> So, that brings me to
> the obvious question: why use phylink for this rather than the phylib
> APIs?

Oleksij is looking at code....

> phylink isn't obsoleting phylib in any way, and phylib does support
> the ability for the PHY to change its MAC side interface (if it didn't
> then PHYs such as 88x3310 and similar wouldn't be usable.)

regards,
Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde           |
Embedded Linux                   | https://www.pengutronix.de  |
Vertretung West/Dortmund         | Phone: +49-231-2826-924     |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-5555 |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus
  2020-10-23 10:56 ` [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Oleksij Rempel
@ 2020-10-23 20:18   ` Andrew Lunn
  2020-10-23 20:53   ` Andrew Lunn
  1 sibling, 0 replies; 15+ messages in thread
From: Andrew Lunn @ 2020-10-23 20:18 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp, David Jander, kernel,
	linux-kernel, netdev, Russell King, mkl, Marek Vasut, linux-can

On Fri, Oct 23, 2020 at 12:56:21PM +0200, Oleksij Rempel wrote:
> 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 <o.rempel@pengutronix.de>
> ---
>  drivers/net/phy/Kconfig       |   8 ++
>  drivers/net/phy/Makefile      |   1 +
>  drivers/net/phy/can_phy_bus.c | 196 ++++++++++++++++++++++++++++++++++

Hi Oleksij

mdio drivers have moved to drivers/net/mdio.

>  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.

Is there anything CAN specific here? Maybe we should just call it a
virtual PHY bus?

	Andrew

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 3/6] net: phy: add CAN interface mode
  2020-10-23 10:56 ` [RFC PATCH v1 3/6] net: phy: add CAN interface mode Oleksij Rempel
@ 2020-10-23 20:24   ` Andrew Lunn
  0 siblings, 0 replies; 15+ messages in thread
From: Andrew Lunn @ 2020-10-23 20:24 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp, David Jander, kernel,
	linux-kernel, netdev, Russell King, mkl, Marek Vasut, linux-can

On Fri, Oct 23, 2020 at 12:56:23PM +0200, Oleksij Rempel wrote:
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  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;

There is nothing stopping you from adding CAN specific PORT_ types.

      Andrew

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 0/6] add initial CAN PHY support
  2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
                   ` (6 preceding siblings ...)
  2020-10-23 11:45 ` [RFC PATCH v1 0/6] add initial CAN PHY support Russell King - ARM Linux admin
@ 2020-10-23 20:30 ` Andrew Lunn
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Lunn @ 2020-10-23 20:30 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp, David Jander, kernel,
	linux-kernel, netdev, Russell King, mkl, Marek Vasut, linux-can

On Fri, Oct 23, 2020 at 12:56:20PM +0200, Oleksij Rempel wrote:
> This patch set is introducing PHY support for CAN.

The device tree binding needs documenting.

It might also help me get my head around the virtual MDIO bus and how
PHYs are added to it.

     Andrew

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus
  2020-10-23 10:56 ` [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Oleksij Rempel
  2020-10-23 20:18   ` Andrew Lunn
@ 2020-10-23 20:53   ` Andrew Lunn
  1 sibling, 0 replies; 15+ messages in thread
From: Andrew Lunn @ 2020-10-23 20:53 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: David S. Miller, Florian Fainelli, Heiner Kallweit,
	Jakub Kicinski, Oliver Hartkopp, David Jander, kernel,
	linux-kernel, netdev, Russell King, mkl, Marek Vasut, linux-can

On Fri, Oct 23, 2020 at 12:56:21PM +0200, Oleksij Rempel wrote:
> 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.

I don't think you are making the best use of the phylib framework.

MDIO busses can be standalone devices, with their own DT nodes. And
that device node can list the PHY devices on the bus.

can_mdio {
	compatible = "virtual,mdio-virtual";
        #address-cells = <1>;
        #size-cells = <0>;

	canphy0: can-phy@0 {
		compatible = "can,generic-transceiver",
		reg = <0>;
	}
	canphy1: can-phy@1 
		compatible = "nxp,tja1051",
		reg = <1>
	}
}

When you call of_mdiobus_register(fmb->mii_bus, np) it will parse this
tree and should create PHY devices for them, and since your PHY driver
has a match function, it should then bind the correct PHY driver.

Your 'MAC' driver then uses phy-handle as normal to point to the PHY.

There is also some interesting overlap here with what Intel posted
recently:

https://www.spinics.net/lists/kernel/msg3706164.html

I'm not sure anything can be shared here, but it is worth looking at
and thinking about.

    Andrew

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-10-23 20:53 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-23 10:56 [RFC PATCH v1 0/6] add initial CAN PHY support Oleksij Rempel
2020-10-23 10:56 ` [RFC PATCH v1 1/6] net: phy: add CAN PHY Virtual Bus Oleksij Rempel
2020-10-23 20:18   ` Andrew Lunn
2020-10-23 20:53   ` Andrew Lunn
2020-10-23 10:56 ` [RFC PATCH v1 2/6] net: phy: add a driver for generic CAN PHYs Oleksij Rempel
2020-10-23 10:56 ` [RFC PATCH v1 3/6] net: phy: add CAN interface mode Oleksij Rempel
2020-10-23 20:24   ` Andrew Lunn
2020-10-23 10:56 ` [RFC PATCH v1 4/6] net: add CAN specific link modes Oleksij Rempel
2020-10-23 10:56 ` [RFC PATCH v1 5/6] can: flexcan: add phylink support Oleksij Rempel
2020-10-23 10:56 ` [RFC PATCH v1 6/6] can: flexcan: add ethtool support Oleksij Rempel
2020-10-23 11:45 ` [RFC PATCH v1 0/6] add initial CAN PHY support Russell King - ARM Linux admin
2020-10-23 12:14   ` Marc Kleine-Budde
2020-10-23 12:22     ` Russell King - ARM Linux admin
2020-10-23 13:04       ` Marc Kleine-Budde
2020-10-23 20:30 ` Andrew Lunn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).