lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <aUq7E4yh0OgTfdxF@vaman>
Date: Tue, 23 Dec 2025 21:23:55 +0530
From: Vinod Koul <vkoul@...nel.org>
To: Théo Lebrun <theo.lebrun@...tlin.com>
Cc: Vladimir Kondratiev <vladimir.kondratiev@...ileye.com>,
	Grégory Clement <gregory.clement@...tlin.com>,
	Rob Herring <robh@...nel.org>,
	Krzysztof Kozlowski <krzk+dt@...nel.org>,
	Conor Dooley <conor+dt@...nel.org>,
	Kishon Vijay Abraham I <kishon@...nel.org>,
	Michael Turquette <mturquette@...libre.com>,
	Stephen Boyd <sboyd@...nel.org>,
	Philipp Zabel <p.zabel@...gutronix.de>,
	Thomas Bogendoerfer <tsbogend@...ha.franken.de>,
	Neil Armstrong <neil.armstrong@...aro.org>,
	linux-mips@...r.kernel.org, devicetree@...r.kernel.org,
	linux-kernel@...r.kernel.org, linux-phy@...ts.infradead.org,
	linux-clk@...r.kernel.org,
	Benoît Monin <benoit.monin@...tlin.com>,
	Tawfik Bayouk <tawfik.bayouk@...ileye.com>,
	Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
	Luca Ceresoli <luca.ceresoli@...tlin.com>
Subject: Re: [PATCH v5 2/7] phy: Add driver for EyeQ5 Ethernet PHY wrapper

On 15-12-25, 17:26, Théo Lebrun wrote:
> EyeQ5 embeds a system-controller called OLB. It features many unrelated
> registers, and some of those are registers used to configure the
> integration of the RGMII/SGMII Cadence PHY used by MACB/GEM instances.
> 
> Wrap in a neat generic PHY provider, exposing two PHYs with standard
> phy_init() / phy_set_mode() / phy_power_on() operations.
> 
> Reviewed-by: Luca Ceresoli <luca.ceresoli@...tlin.com>
> Signed-off-by: Théo Lebrun <theo.lebrun@...tlin.com>
> ---
>  MAINTAINERS                 |   1 +
>  drivers/phy/Kconfig         |  13 +++
>  drivers/phy/Makefile        |   1 +
>  drivers/phy/phy-eyeq5-eth.c | 249 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 264 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5b11839cba9d..2f67ec9fad57 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17605,6 +17605,7 @@ F:	arch/mips/boot/dts/mobileye/
>  F:	arch/mips/configs/eyeq5_defconfig
>  F:	arch/mips/mobileye/board-epm5.its.S
>  F:	drivers/clk/clk-eyeq.c
> +F:	drivers/phy/phy-eyeq5-eth.c
>  F:	drivers/pinctrl/pinctrl-eyeq5.c
>  F:	drivers/reset/reset-eyeq.c
>  F:	include/dt-bindings/clock/mobileye,eyeq5-clk.h
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 678dd0452f0a..1aa6eff12dbc 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -101,6 +101,19 @@ config PHY_NXP_PTN3222
>  	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
>  	  Speed and High Speed.
>  
> +config PHY_EYEQ5_ETH

sorted please

> +	tristate "Ethernet PHY Driver on EyeQ5"
> +	depends on OF
> +	depends on MACH_EYEQ5 || COMPILE_TEST
> +	select AUXILIARY_BUS
> +	select GENERIC_PHY
> +	default MACH_EYEQ5

hmmm why should it be default? Maybe add this is respective defconfig for
platform instead..?

> +	help
> +	  Enable this to support the Ethernet PHY integrated on EyeQ5.
> +	  It supports both RGMII and SGMII. Registers are located in a
> +	  shared register region called OLB. If M is selected, the
> +	  module will be called phy-eyeq5-eth.
> +
>  source "drivers/phy/allwinner/Kconfig"
>  source "drivers/phy/amlogic/Kconfig"
>  source "drivers/phy/broadcom/Kconfig"
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index bfb27fb5a494..8289497ece55 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
>  obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
>  obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
>  obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
> +obj-$(CONFIG_PHY_EYEQ5_ETH)		+= phy-eyeq5-eth.o

sorted please

>  obj-y					+= allwinner/	\
>  					   amlogic/	\
>  					   broadcom/	\
> diff --git a/drivers/phy/phy-eyeq5-eth.c b/drivers/phy/phy-eyeq5-eth.c
> new file mode 100644
> index 000000000000..6e28f7e24835
> --- /dev/null
> +++ b/drivers/phy/phy-eyeq5-eth.c
> @@ -0,0 +1,249 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/auxiliary_bus.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/gfp_types.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/phy.h>
> +#include <linux/phy/phy.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#define EQ5_PHY_COUNT	2
> +
> +#define EQ5_PHY0_GP	0x128
> +#define EQ5_PHY1_GP	0x12c
> +#define EQ5_PHY0_SGMII	0x134
> +#define EQ5_PHY1_SGMII	0x138
> +
> +#define EQ5_GP_TX_SWRST_DIS	BIT(0)		// Tx SW reset
> +#define EQ5_GP_TX_M_CLKE	BIT(1)		// Tx M clock enable
> +#define EQ5_GP_SYS_SWRST_DIS	BIT(2)		// Sys SW reset
> +#define EQ5_GP_SYS_M_CLKE	BIT(3)		// Sys clock enable
> +#define EQ5_GP_SGMII_MODE	BIT(4)		// SGMII mode
> +#define EQ5_GP_RGMII_DRV	GENMASK(8, 5)	// RGMII drive strength
> +
> +#define EQ5_SGMII_PWR_EN	BIT(0)
> +#define EQ5_SGMII_RST_DIS	BIT(1)
> +#define EQ5_SGMII_PLL_EN	BIT(2)
> +#define EQ5_SGMII_SIG_DET_SW	BIT(3)
> +#define EQ5_SGMII_PWR_STATE	BIT(4)
> +#define EQ5_SGMII_PLL_ACK	BIT(18)
> +#define EQ5_SGMII_PWR_STATE_ACK	GENMASK(24, 20)
> +
> +struct eq5_phy_inst {
> +	struct eq5_phy_private	*priv;
> +	struct phy		*phy;
> +	void __iomem		*gp, *sgmii;
> +	phy_interface_t		phy_interface;
> +};
> +
> +struct eq5_phy_private {
> +	struct device		*dev;
> +	struct eq5_phy_inst	phys[EQ5_PHY_COUNT];
> +};
> +
> +static int eq5_phy_init(struct phy *phy)
> +{
> +	struct eq5_phy_inst *inst = phy_get_drvdata(phy);
> +	struct eq5_phy_private *priv = inst->priv;
> +	struct device *dev = priv->dev;
> +	u32 reg;
> +
> +	dev_dbg(dev, "phy_init(inst=%td)\n", inst - priv->phys);
> +
> +	writel(0, inst->gp);
> +	writel(0, inst->sgmii);
> +
> +	udelay(5);
> +
> +	reg = readl(inst->gp) | EQ5_GP_TX_SWRST_DIS | EQ5_GP_TX_M_CLKE |
> +	      EQ5_GP_SYS_SWRST_DIS | EQ5_GP_SYS_M_CLKE |
> +	      FIELD_PREP(EQ5_GP_RGMII_DRV, 0x9);
> +	writel(reg, inst->gp);
> +
> +	return 0;
> +}
> +
> +static int eq5_phy_exit(struct phy *phy)
> +{
> +	struct eq5_phy_inst *inst = phy_get_drvdata(phy);
> +	struct eq5_phy_private *priv = inst->priv;
> +	struct device *dev = priv->dev;
> +
> +	dev_dbg(dev, "phy_exit(inst=%td)\n", inst - priv->phys);
> +
> +	writel(0, inst->gp);
> +	writel(0, inst->sgmii);
> +	udelay(5);

this is same patter in init as well...?

> +
> +	return 0;
> +}
> +
> +static int eq5_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
> +{
> +	struct eq5_phy_inst *inst = phy_get_drvdata(phy);
> +	struct eq5_phy_private *priv = inst->priv;
> +	struct device *dev = priv->dev;
> +
> +	dev_dbg(dev, "phy_set_mode(inst=%td, mode=%d, submode=%d)\n",
> +		inst - priv->phys, mode, submode);

these are good for debug but not for upstream, please drop

> +
> +	if (mode != PHY_MODE_ETHERNET)
> +		return -EOPNOTSUPP;
> +
> +	if (!phy_interface_mode_is_rgmii(submode) &&
> +	    submode != PHY_INTERFACE_MODE_SGMII)
> +		return -EOPNOTSUPP;
> +
> +	inst->phy_interface = submode;
> +	return 0;
> +}
> +
> +static int eq5_phy_power_on(struct phy *phy)
> +{
> +	struct eq5_phy_inst *inst = phy_get_drvdata(phy);
> +	struct eq5_phy_private *priv = inst->priv;
> +	struct device *dev = priv->dev;
> +	u32 reg;
> +
> +	dev_dbg(dev, "phy_power_on(inst=%td)\n", inst - priv->phys);
> +
> +	if (inst->phy_interface == PHY_INTERFACE_MODE_SGMII) {
> +		writel(readl(inst->gp) | EQ5_GP_SGMII_MODE, inst->gp);
> +
> +		reg = EQ5_SGMII_PWR_EN | EQ5_SGMII_RST_DIS | EQ5_SGMII_PLL_EN;
> +		writel(reg, inst->sgmii);
> +
> +		if (readl_poll_timeout(inst->sgmii, reg,
> +				       reg & EQ5_SGMII_PLL_ACK, 1, 100)) {
> +			dev_err(dev, "PLL timeout\n");
> +			return -ETIMEDOUT;
> +		}
> +
> +		reg = readl(inst->sgmii);
> +		reg |= EQ5_SGMII_PWR_STATE | EQ5_SGMII_SIG_DET_SW;
> +		writel(reg, inst->sgmii);
> +	} else {
> +		writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp);
> +		writel(0, inst->sgmii);
> +	}
> +
> +	return 0;
> +}
> +
> +static int eq5_phy_power_off(struct phy *phy)
> +{
> +	struct eq5_phy_inst *inst = phy_get_drvdata(phy);
> +	struct eq5_phy_private *priv = inst->priv;
> +	struct device *dev = priv->dev;
> +
> +	dev_dbg(dev, "phy_power_off(inst=%td)\n", inst - priv->phys);
> +
> +	writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp);
> +	writel(0, inst->sgmii);
> +
> +	return 0;
> +}
> +
> +static const struct phy_ops eq5_phy_ops = {
> +	.init		= eq5_phy_init,
> +	.exit		= eq5_phy_exit,
> +	.set_mode	= eq5_phy_set_mode,
> +	.power_on	= eq5_phy_power_on,
> +	.power_off	= eq5_phy_power_off,
> +};
> +
> +static struct phy *eq5_phy_xlate(struct device *dev,
> +				 const struct of_phandle_args *args)
> +{
> +	struct eq5_phy_private *priv = dev_get_drvdata(dev);
> +
> +	if (args->args_count != 1 || args->args[0] >= EQ5_PHY_COUNT)
> +		return ERR_PTR(-EINVAL);
> +
> +	return priv->phys[args->args[0]].phy;
> +}
> +
> +static int eq5_phy_probe_phy(struct eq5_phy_private *priv, unsigned int index,
> +			     void __iomem *base, unsigned int gp,
> +			     unsigned int sgmii)
> +{
> +	struct eq5_phy_inst *inst = &priv->phys[index];
> +	struct device *dev = priv->dev;
> +	struct phy *phy;
> +
> +	phy = devm_phy_create(dev, dev->of_node, &eq5_phy_ops);
> +	if (IS_ERR(phy))
> +		return dev_err_probe(dev, PTR_ERR(phy),
> +				     "failed to create PHY %u\n", index);
> +
> +	inst->priv = priv;
> +	inst->phy = phy;
> +	inst->gp = base + gp;
> +	inst->sgmii = base + sgmii;
> +	inst->phy_interface = PHY_INTERFACE_MODE_NA;
> +	phy_set_drvdata(phy, inst);
> +
> +	return 0;
> +}
> +
> +static int eq5_phy_probe(struct auxiliary_device *adev,
> +			 const struct auxiliary_device_id *id)
> +{
> +	struct device *dev = &adev->dev;
> +	struct phy_provider *provider;
> +	struct eq5_phy_private *priv;
> +	void __iomem *base;
> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	dev_set_drvdata(dev, priv);
> +
> +	base = (void __iomem *)dev_get_platdata(dev);

no need to cast for void *
-- 
~Vinod

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ