* [PATCH v3 phy-next 00/24] Split Generic PHY consumer and provider API
From: Vladimir Oltean @ 2026-03-09 19:08 UTC (permalink / raw)
To: linux-phy
Cc: Vinod Koul, Neil Armstrong, dri-devel, freedreno,
linux-arm-kernel, linux-arm-msm, linux-can, linux-gpio, linux-ide,
linux-kernel, linux-media, linux-pci, linux-renesas-soc,
linux-riscv, linux-rockchip, linux-samsung-soc, linux-scsi,
linux-sunxi, linux-tegra, linux-usb, netdev, spacemit,
UNGLinuxDriver, Abhinav Kumar, Alexandre Belloni,
André Draszik, Andrew Lunn, Andrzej Hajda, Andy Yan,
Bjorn Helgaas, Chanho Park, Chen-Yu Tsai, Claudiu Beznea,
Damien Le Moal, Daniel Machon, David Airlie, David S. Miller,
Dmitry Baryshkov, Eric Dumazet, Fabio Estevam, Frank Li,
Geert Uytterhoeven, Greg Kroah-Hartman, Heiko Stübner,
Inki Dae, Jagan Teki, Jakub Kicinski, Jernej Skrabec,
Jessica Zhang, Joe Perches, Jonas Karlman, Jonathan Hunter,
Kevin Xie, Krzysztof Kozlowski, Krzysztof Wilczyński,
Laurent Pinchart, Linus Walleij, Lorenzo Pieralisi,
Maarten Lankhorst, Magnus Damm, Manivannan Sadhasivam,
Marc Kleine-Budde, Marek Szyprowski, Marijn Suijten,
Markus Schneider-Pargmann, Mauro Carvalho Chehab, Maxime Ripard,
Michael Dege, Nicolas Ferre, Niklas Cassel, Paolo Abeni,
Pengutronix Kernel Team, Peter Chen, Peter Griffin, Rob Clark,
Robert Foss, Rob Herring, Russell King (Oracle), Samuel Holland,
Sandy Huang, Sascha Hauer, Sean Paul, Sebastian Reichel,
Shawn Guo, Shawn Lin, Simona Vetter, Steen Hegelund,
Thierry Reding, Thinh Nguyen, Thomas Zimmermann, Tudor Ambarus,
Vincent Mailhol, Yixun Lan, Yoshihiro Shimoda
The biggest problem requiring this split is the fact that consumer
drivers poke around in struct phy, accessing fields which shouldn't be
visible to them. Follow the example of mux, gpio, iio, spi offload,
pwrsec, pinctrl and regulator, which each expose separate headers for
consumers and providers.
Some off-list discussions were had with Vinod Koul regarding the 3 PHY
providers outside the drivers/phy/ subsystem. It was agreed that it is
desirable to relocate them to drivers/phy/, rather than to publish
phy-provider.h to include/linux/phy/ for liberal use. Only phy.h and
(new) phy-props.h - consumer-facing headers - stay there.
The hope is that developers get a hint when they need to include the
wrong header to get their job done.
If that fails, patch 24/24 adds a regex in the MAINTAINERS entry that
ensures linux-phy is copied on all Generic PHY patches, for an extra set
of eyes.
The series is formatted on linux-phy/next for build testing, but is
intended to be applied on top of commit
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=4ff5801f45b494ad8251a16ec06c9f303ed3b9a0
which is v7.0-rc1 + 1 patch, and then merged into linux-phy/next.
The idea being that it's better to resolve the merge conflict early.
There are 4 expected conflicts, details in the conflicting patches
(21/24 and 22/24).
Requested merge strategy, I hope this works for everyone:
- Subsystem maintainers ACK their affected portions
- Entire series goes through linux-phy
- linux-phy provides stable tag
- (optionally) Said tag is merged back into affected subsystem 'next'
branches. Those who prefer can handle merge conflicts when they send
their PR.
Detailed change log in patches, summary below.
v2->v3:
- remove unused variable in PCI after device link removal
- update MAINTAINERS regex pattern to escape forward slashes
- add more people to CC list
- provide conflict resolution
v1->v2:
- split "phy: include PHY provider header" into smaller chunks to work
around mailing list moderation due to patch size
- improve MAINTAINERS regex pattern
- make all PHY attribute helpers NULL-tolerant. Not just the new
phy_get_bus_width(), but also retroactively, the existing ones.
- fixed the temporary include path from <linux/phy/phy.h> to
"phy-provider.h", removed anyway by the end of the series
- logical bug fixes in the PCI controller <-> PHY device link removal
and Exynos UFS PHY API rework
In case anyone wants to test the series, here it is on top of linux-phy/next:
https://github.com/vladimiroltean/linux/tree/phy-split-consumer-provider-v3
I've also test-applied it on v7.0-rc1 and provided conflict resolution
with net-next and with linux-phy/next:
https://github.com/vladimiroltean/linux/commits/phy-split-consumer-provider-merge/
v2 at:
https://lore.kernel.org/linux-phy/20260308114009.2546587-1-vladimir.oltean@nxp.com/
v1 at:
https://lore.kernel.org/linux-phy/20260304175735.2660419-13-vladimir.oltean@nxp.com/
Cc: Abhinav Kumar <abhinav.kumar@linux.dev>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: "André Draszik" <andre.draszik@linaro.org>
Cc: Andrew Lunn <andrew+netdev@lunn.ch>
Cc: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Andy Yan <andy.yan@rock-chips.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Chanho Park <chanho61.park@samsung.com>
Cc: Chen-Yu Tsai <wens@kernel.org>
Cc: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Cc: Damien Le Moal <dlemoal@kernel.org>
Cc: Daniel Machon <daniel.machon@microchip.com>
Cc: David Airlie <airlied@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Dmitry Baryshkov <lumag@kernel.org>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Frank Li <Frank.Li@nxp.com>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Heiko Stübner" <heiko@sntech.de>
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Jernej Skrabec <jernej.skrabec@gmail.com>
Cc: Jessica Zhang <jesszhan0024@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Jonas Karlman <jonas@kwiboo.se>
Cc: Jonathan Hunter <jonathanh@nvidia.com>
Cc: Kevin Xie <kevin.xie@starfivetech.com>
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
Cc: Linus Walleij <linusw@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Magnus Damm <magnus.damm@gmail.com>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Marijn Suijten <marijn.suijten@somainline.org>
Cc: Markus Schneider-Pargmann <msp@baylibre.com>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Michael Dege <michael.dege@renesas.com>
Cc: Neil Armstrong <neil.armstrong@linaro.org>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Niklas Cassel <cassel@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
Cc: Peter Chen <peter.chen@kernel.org>
Cc: Peter Griffin <peter.griffin@linaro.org>
Cc: Rob Clark <robin.clark@oss.qualcomm.com>
Cc: Robert Foss <rfoss@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
Cc: Samuel Holland <samuel@sholland.org>
Cc: Sandy Huang <hjc@rock-chips.com>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Sean Paul <sean@poorly.run>
Cc: Sebastian Reichel <sre@kernel.org>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Shawn Lin <shawn.lin@rock-chips.com>
Cc: Simona Vetter <simona@ffwll.ch>
Cc: Steen Hegelund <Steen.Hegelund@microchip.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Tudor Ambarus <tudor.ambarus@linaro.org>
Cc: Vincent Mailhol <mailhol@kernel.org>
Cc: Yixun Lan <dlan@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Vladimir Oltean (24):
ata: add <linux/pm_runtime.h> where missing
PCI: Add missing headers transitively included by <linux/phy/phy.h>
usb: add missing headers transitively included by <linux/phy/phy.h>
drm: add <linux/pm_runtime.h> where missing
phy: add <linux/pm_runtime.h> where missing
phy: spacemit: include missing <linux/phy/phy.h>
net: lan969x: include missing <linux/of.h>
PCI: Remove device links to PHY
ufs: exynos: stop poking into struct phy guts
drm/rockchip: dw_hdmi: avoid direct dereference of phy->dev.of_node
drm/msm/dp: remove debugging prints with internal struct phy state
phy: move provider API out of public <linux/phy/phy.h>
phy: make phy_get_mode(), phy_(get|set)_bus_width() NULL tolerant
phy: introduce phy_get_max_link_rate() helper for consumers
drm/rockchip: dsi: include PHY provider header
drm: bridge: cdns-mhdp8546: use consumer API for getting PHY bus width
media: sunxi: a83-mips-csi2: include PHY provider header
net: renesas: rswitch: include PHY provider header
pinctrl: tegra-xusb: include PHY provider header
power: supply: cpcap-charger: include missing <linux/property.h>
phy: include PHY provider header (1/2)
phy: include PHY provider header (2/2)
phy: remove temporary provider compatibility from consumer header
MAINTAINERS: add regexes for linux-phy
MAINTAINERS | 11 +
drivers/ata/ahci.c | 1 +
drivers/ata/ahci_brcm.c | 1 +
drivers/ata/ahci_ceva.c | 1 +
drivers/ata/ahci_qoriq.c | 1 +
drivers/ata/libahci.c | 1 +
.../drm/bridge/analogix/analogix_dp_core.c | 1 +
.../drm/bridge/cadence/cdns-mhdp8546-core.c | 7 +-
drivers/gpu/drm/bridge/nwl-dsi.c | 1 +
drivers/gpu/drm/bridge/samsung-dsim.c | 1 +
drivers/gpu/drm/bridge/synopsys/dw-dp.c | 2 +-
drivers/gpu/drm/msm/dp/dp_aux.c | 1 +
drivers/gpu/drm/msm/dp/dp_ctrl.c | 18 -
drivers/gpu/drm/rockchip/cdn-dp-core.c | 1 +
.../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 1 +
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 25 +-
.../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 2 +-
drivers/net/can/at91_can.c | 3 +-
drivers/net/can/flexcan/flexcan-core.c | 3 +-
drivers/net/can/m_can/m_can_platform.c | 3 +-
drivers/net/can/rcar/rcar_canfd.c | 3 +-
.../microchip/sparx5/lan969x/lan969x_rgmii.c | 1 +
drivers/net/ethernet/renesas/rswitch_main.c | 1 +
.../controller/cadence/pcie-cadence-plat.c | 4 -
drivers/pci/controller/cadence/pcie-cadence.c | 16 +-
drivers/pci/controller/cadence/pcie-cadence.h | 2 -
drivers/pci/controller/dwc/pci-dra7xx.c | 16 -
drivers/pci/controller/dwc/pci-keystone.c | 32 +-
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 1 +
drivers/pci/controller/dwc/pcie-histb.c | 1 +
drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 +
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 2 +
drivers/pci/controller/dwc/pcie-tegra194.c | 1 +
drivers/pci/controller/pci-tegra.c | 1 +
drivers/pci/controller/pcie-rockchip-host.c | 1 +
drivers/pci/controller/plda/pcie-starfive.c | 1 +
drivers/phy/allwinner/phy-sun4i-usb.c | 3 +-
drivers/phy/allwinner/phy-sun50i-usb3.c | 3 +-
drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 4 +-
drivers/phy/allwinner/phy-sun9i-usb.c | 3 +-
drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c | 2 +
.../amlogic/phy-meson-axg-mipi-pcie-analog.c | 3 +-
drivers/phy/amlogic/phy-meson-axg-pcie.c | 2 +
.../amlogic/phy-meson-g12a-mipi-dphy-analog.c | 3 +-
drivers/phy/amlogic/phy-meson-g12a-usb2.c | 2 +
.../phy/amlogic/phy-meson-g12a-usb3-pcie.c | 3 +-
drivers/phy/amlogic/phy-meson-gxl-usb2.c | 3 +-
drivers/phy/amlogic/phy-meson8-hdmi-tx.c | 3 +-
drivers/phy/amlogic/phy-meson8b-usb2.c | 3 +-
drivers/phy/apple/atc.c | 3 +-
drivers/phy/broadcom/phy-bcm-cygnus-pcie.c | 3 +-
drivers/phy/broadcom/phy-bcm-kona-usb2.c | 4 +-
drivers/phy/broadcom/phy-bcm-ns-usb2.c | 3 +-
drivers/phy/broadcom/phy-bcm-ns-usb3.c | 3 +-
drivers/phy/broadcom/phy-bcm-ns2-pcie.c | 3 +-
drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c | 3 +-
drivers/phy/broadcom/phy-bcm-sr-pcie.c | 3 +-
drivers/phy/broadcom/phy-bcm-sr-usb.c | 3 +-
drivers/phy/broadcom/phy-bcm63xx-usbh.c | 3 +-
drivers/phy/broadcom/phy-brcm-sata.c | 3 +-
drivers/phy/broadcom/phy-brcm-usb.c | 2 +-
drivers/phy/cadence/cdns-dphy-rx.c | 3 +-
drivers/phy/cadence/cdns-dphy.c | 4 +-
drivers/phy/cadence/phy-cadence-salvo.c | 3 +-
drivers/phy/cadence/phy-cadence-sierra.c | 3 +-
drivers/phy/cadence/phy-cadence-torrent.c | 3 +-
drivers/phy/canaan/phy-k230-usb.c | 3 +-
drivers/phy/eswin/phy-eic7700-sata.c | 3 +-
.../phy/freescale/phy-fsl-imx8-mipi-dphy.c | 3 +-
drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 4 +-
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 3 +-
drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 6 +-
.../phy/freescale/phy-fsl-imx8qm-lvds-phy.c | 3 +-
drivers/phy/freescale/phy-fsl-lynx-28g.c | 3 +-
drivers/phy/hisilicon/phy-hi3660-usb3.c | 3 +-
drivers/phy/hisilicon/phy-hi3670-pcie.c | 3 +-
drivers/phy/hisilicon/phy-hi3670-usb3.c | 3 +-
drivers/phy/hisilicon/phy-hi6220-usb.c | 3 +-
drivers/phy/hisilicon/phy-hisi-inno-usb2.c | 4 +-
drivers/phy/hisilicon/phy-histb-combphy.c | 3 +-
drivers/phy/hisilicon/phy-hix5hd2-sata.c | 3 +-
drivers/phy/ingenic/phy-ingenic-usb.c | 3 +-
drivers/phy/intel/phy-intel-keembay-emmc.c | 3 +-
drivers/phy/intel/phy-intel-keembay-usb.c | 3 +-
drivers/phy/intel/phy-intel-lgm-combo.c | 4 +-
drivers/phy/intel/phy-intel-lgm-emmc.c | 3 +-
drivers/phy/lantiq/phy-lantiq-rcu-usb2.c | 3 +-
drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c | 4 +-
drivers/phy/marvell/phy-armada375-usb2.c | 3 +-
drivers/phy/marvell/phy-armada38x-comphy.c | 3 +-
drivers/phy/marvell/phy-berlin-sata.c | 3 +-
drivers/phy/marvell/phy-berlin-usb.c | 3 +-
drivers/phy/marvell/phy-mmp3-hsic.c | 3 +-
drivers/phy/marvell/phy-mmp3-usb.c | 3 +-
drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 3 +-
drivers/phy/marvell/phy-mvebu-a3700-utmi.c | 3 +-
drivers/phy/marvell/phy-mvebu-cp110-comphy.c | 3 +-
drivers/phy/marvell/phy-mvebu-cp110-utmi.c | 3 +-
drivers/phy/marvell/phy-mvebu-sata.c | 3 +-
drivers/phy/marvell/phy-pxa-28nm-hsic.c | 3 +-
drivers/phy/marvell/phy-pxa-28nm-usb2.c | 3 +-
drivers/phy/marvell/phy-pxa-usb.c | 3 +-
drivers/phy/mediatek/phy-mtk-dp.c | 3 +-
drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c | 1 -
drivers/phy/mediatek/phy-mtk-hdmi.h | 3 +-
drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c | 2 +-
drivers/phy/mediatek/phy-mtk-mipi-dsi.h | 3 +-
drivers/phy/mediatek/phy-mtk-pcie.c | 2 +-
drivers/phy/mediatek/phy-mtk-tphy.c | 2 +-
drivers/phy/mediatek/phy-mtk-ufs.c | 2 +-
drivers/phy/mediatek/phy-mtk-xfi-tphy.c | 2 +-
drivers/phy/mediatek/phy-mtk-xsphy.c | 2 +-
drivers/phy/microchip/lan966x_serdes.c | 4 +-
drivers/phy/microchip/sparx5_serdes.c | 2 +-
drivers/phy/motorola/phy-cpcap-usb.c | 3 +-
drivers/phy/motorola/phy-mapphone-mdm6600.c | 5 +-
drivers/phy/mscc/phy-ocelot-serdes.c | 3 +-
drivers/phy/nuvoton/phy-ma35d1-usb2.c | 3 +-
drivers/phy/phy-airoha-pcie.c | 2 +-
drivers/phy/phy-can-transceiver.c | 3 +-
drivers/phy/phy-core-mipi-dphy.c | 4 +-
drivers/phy/phy-core.c | 52 ++
drivers/phy/phy-google-usb.c | 4 +-
drivers/phy/phy-lpc18xx-usb-otg.c | 3 +-
drivers/phy/phy-nxp-ptn3222.c | 3 +-
drivers/phy/phy-pistachio-usb.c | 4 +-
drivers/phy/phy-provider.h | 256 +++++++++
drivers/phy/phy-snps-eusb2.c | 2 +
drivers/phy/phy-xgene.c | 3 +-
drivers/phy/qualcomm/phy-ath79-usb.c | 3 +-
drivers/phy/qualcomm/phy-qcom-apq8064-sata.c | 3 +-
drivers/phy/qualcomm/phy-qcom-edp.c | 3 +-
.../phy/qualcomm/phy-qcom-eusb2-repeater.c | 3 +-
drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c | 3 +-
drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c | 3 +-
drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 3 +-
drivers/phy/qualcomm/phy-qcom-m31-eusb2.c | 2 +
drivers/phy/qualcomm/phy-qcom-m31.c | 3 +-
drivers/phy/qualcomm/phy-qcom-pcie2.c | 3 +-
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 4 +-
.../phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c | 3 +-
drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 3 +-
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 3 +-
.../phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 4 +-
drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 4 +-
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 4 +-
drivers/phy/qualcomm/phy-qcom-qusb2.c | 5 +-
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 3 +-
drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c | 4 +-
.../phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c | 3 +-
drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c | 3 +-
drivers/phy/qualcomm/phy-qcom-usb-hs.c | 3 +-
drivers/phy/qualcomm/phy-qcom-usb-hsic.c | 3 +-
drivers/phy/qualcomm/phy-qcom-usb-ss.c | 3 +-
drivers/phy/ralink/phy-mt7621-pci.c | 3 +-
drivers/phy/ralink/phy-ralink-usb.c | 3 +-
drivers/phy/realtek/phy-rtk-usb2.c | 3 +-
drivers/phy/realtek/phy-rtk-usb3.c | 3 +-
drivers/phy/renesas/phy-rcar-gen2.c | 3 +-
drivers/phy/renesas/phy-rcar-gen3-pcie.c | 4 +-
drivers/phy/renesas/phy-rcar-gen3-usb2.c | 3 +-
drivers/phy/renesas/phy-rcar-gen3-usb3.c | 3 +-
drivers/phy/renesas/phy-rzg3e-usb3.c | 3 +-
drivers/phy/renesas/r8a779f0-ether-serdes.c | 4 +-
drivers/phy/rockchip/phy-rockchip-dp.c | 3 +-
drivers/phy/rockchip/phy-rockchip-dphy-rx0.c | 3 +-
drivers/phy/rockchip/phy-rockchip-emmc.c | 3 +-
.../phy/rockchip/phy-rockchip-inno-csidphy.c | 3 +-
.../phy/rockchip/phy-rockchip-inno-dsidphy.c | 4 +-
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 2 +
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 3 +-
.../rockchip/phy-rockchip-naneng-combphy.c | 3 +-
drivers/phy/rockchip/phy-rockchip-pcie.c | 2 +-
.../phy/rockchip/phy-rockchip-samsung-dcphy.c | 3 +-
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 +
.../phy/rockchip/phy-rockchip-snps-pcie3.c | 3 +-
drivers/phy/rockchip/phy-rockchip-typec.c | 5 +-
drivers/phy/rockchip/phy-rockchip-usb.c | 3 +-
drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 +
drivers/phy/samsung/phy-exynos-dp-video.c | 3 +-
drivers/phy/samsung/phy-exynos-mipi-video.c | 3 +-
drivers/phy/samsung/phy-exynos-pcie.c | 3 +-
drivers/phy/samsung/phy-exynos4210-usb2.c | 3 +-
drivers/phy/samsung/phy-exynos4x12-usb2.c | 3 +-
drivers/phy/samsung/phy-exynos5-usbdrd.c | 2 +
drivers/phy/samsung/phy-exynos5250-sata.c | 3 +-
drivers/phy/samsung/phy-exynos5250-usb2.c | 3 +-
drivers/phy/samsung/phy-s5pv210-usb2.c | 3 +-
drivers/phy/samsung/phy-samsung-ufs.c | 2 +-
drivers/phy/samsung/phy-samsung-ufs.h | 3 +-
drivers/phy/samsung/phy-samsung-usb2.c | 2 +
drivers/phy/samsung/phy-samsung-usb2.h | 3 +-
drivers/phy/socionext/phy-uniphier-ahci.c | 3 +-
drivers/phy/socionext/phy-uniphier-pcie.c | 3 +-
drivers/phy/socionext/phy-uniphier-usb2.c | 3 +-
drivers/phy/socionext/phy-uniphier-usb3hs.c | 3 +-
drivers/phy/socionext/phy-uniphier-usb3ss.c | 3 +-
drivers/phy/sophgo/phy-cv1800-usb2.c | 3 +-
drivers/phy/spacemit/phy-k1-pcie.c | 4 +-
drivers/phy/spacemit/phy-k1-usb2.c | 2 +
drivers/phy/st/phy-miphy28lp.c | 4 +-
drivers/phy/st/phy-spear1310-miphy.c | 3 +-
drivers/phy/st/phy-spear1340-miphy.c | 3 +-
drivers/phy/st/phy-stih407-usb.c | 3 +-
drivers/phy/st/phy-stm32-combophy.c | 3 +-
drivers/phy/st/phy-stm32-usbphyc.c | 2 +
drivers/phy/starfive/phy-jh7110-dphy-rx.c | 3 +-
drivers/phy/starfive/phy-jh7110-dphy-tx.c | 3 +-
drivers/phy/starfive/phy-jh7110-pcie.c | 3 +-
drivers/phy/starfive/phy-jh7110-usb.c | 3 +-
drivers/phy/sunplus/phy-sunplus-usb2.c | 3 +-
drivers/phy/tegra/phy-tegra194-p2u.c | 3 +-
drivers/phy/tegra/xusb-tegra124.c | 2 +-
drivers/phy/tegra/xusb-tegra186.c | 2 +-
drivers/phy/tegra/xusb-tegra210.c | 2 +-
drivers/phy/tegra/xusb.c | 2 +-
drivers/phy/ti/phy-am654-serdes.c | 3 +-
drivers/phy/ti/phy-da8xx-usb.c | 3 +-
drivers/phy/ti/phy-dm816x-usb.c | 3 +-
drivers/phy/ti/phy-gmii-sel.c | 3 +-
drivers/phy/ti/phy-omap-usb2.c | 3 +-
drivers/phy/ti/phy-ti-pipe3.c | 3 +-
drivers/phy/ti/phy-tusb1210.c | 1 +
drivers/phy/ti/phy-twl4030-usb.c | 3 +-
drivers/phy/xilinx/phy-zynqmp.c | 4 +-
drivers/pinctrl/tegra/pinctrl-tegra-xusb.c | 2 +-
drivers/power/supply/cpcap-charger.c | 1 +
drivers/ufs/host/ufs-exynos.c | 24 +-
drivers/ufs/host/ufs-exynos.h | 1 +
drivers/usb/chipidea/ci_hdrc_imx.c | 1 +
drivers/usb/core/hcd.c | 1 +
drivers/usb/dwc3/dwc3-generic-plat.c | 1 +
drivers/usb/dwc3/gadget.c | 1 +
include/linux/phy/phy-props.h | 75 +++
include/linux/phy/phy-sun4i-usb.h | 2 +-
include/linux/phy/phy.h | 497 ++++--------------
include/linux/phy/ulpi_phy.h | 2 +-
237 files changed, 941 insertions(+), 705 deletions(-)
create mode 100644 drivers/phy/phy-provider.h
create mode 100644 include/linux/phy/phy-props.h
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v2 net-next 5/5] net: phy: move remaining provider code to mdio_bus_provider.c
From: Heiner Kallweit @ 2026-03-09 17:06 UTC (permalink / raw)
To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
Jakub Kicinski, David Miller, Eric Dumazet, Bjorn Andersson,
Michael Turquette, Stephen Boyd, Vinod Koul, Neil Armstrong
Cc: netdev@vger.kernel.org, Philipp Zabel, linux-arm-msm, linux-clk,
linux-phy
In-Reply-To: <9d5724bc-e525-4f8f-b3f8-b16dd5a1164e@gmail.com>
This moves definition of mdio_bus class and bus_type to the provider
side, what allows to make them private to libphy.
As a prerequisite MDIO statistics handling is moved to the
provider side as well.
Note: This patch causes a checkpatch error "Macros with complex values
should be enclosed in parentheses" for
MDIO_BUS_STATS_ADDR_ATTR_GROUP. I consider this a false positive
here, in addition the patch just moves existing code.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- explain false positive checkpatch error
---
drivers/net/phy/mdio_bus.c | 282 ----------------------------
drivers/net/phy/mdio_bus_provider.c | 275 +++++++++++++++++++++++++++
drivers/net/phy/phylib-internal.h | 3 +
include/linux/phy.h | 3 -
4 files changed, 278 insertions(+), 285 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 9fb47332602..00d0e4159e9 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -10,20 +10,14 @@
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/etherdevice.h>
#include <linux/ethtool.h>
-#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/of_device.h>
-#include <linux/of_mdio.h>
#include <linux/phy.h>
-#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -64,218 +58,6 @@ bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
}
EXPORT_SYMBOL(mdiobus_is_registered_device);
-/**
- * mdiobus_release - mii_bus device release callback
- * @d: the target struct device that contains the mii_bus
- *
- * Description: called when the last reference to an mii_bus is
- * dropped, to free the underlying memory.
- */
-static void mdiobus_release(struct device *d)
-{
- struct mii_bus *bus = to_mii_bus(d);
-
- WARN(bus->state != MDIOBUS_RELEASED &&
- /* for compatibility with error handling in drivers */
- bus->state != MDIOBUS_ALLOCATED,
- "%s: not in RELEASED or ALLOCATED state\n",
- bus->id);
-
- if (bus->state == MDIOBUS_RELEASED)
- fwnode_handle_put(dev_fwnode(d));
-
- kfree(bus);
-}
-
-struct mdio_bus_stat_attr {
- struct device_attribute attr;
- int address;
- unsigned int field_offset;
-};
-
-static struct mdio_bus_stat_attr *to_sattr(struct device_attribute *attr)
-{
- return container_of(attr, struct mdio_bus_stat_attr, attr);
-}
-
-static u64 mdio_bus_get_stat(struct mdio_bus_stats *s, unsigned int offset)
-{
- const u64_stats_t *stats = (const void *)s + offset;
- unsigned int start;
- u64 val = 0;
-
- do {
- start = u64_stats_fetch_begin(&s->syncp);
- val = u64_stats_read(stats);
- } while (u64_stats_fetch_retry(&s->syncp, start));
-
- return val;
-}
-
-static ssize_t mdio_bus_stat_field_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct mdio_bus_stat_attr *sattr = to_sattr(attr);
- struct mii_bus *bus = to_mii_bus(dev);
- u64 val = 0;
-
- if (sattr->address < 0) {
- /* get global stats */
- for (int i = 0; i < PHY_MAX_ADDR; i++)
- val += mdio_bus_get_stat(&bus->stats[i],
- sattr->field_offset);
- } else {
- val = mdio_bus_get_stat(&bus->stats[sattr->address],
- sattr->field_offset);
- }
-
- return sysfs_emit(buf, "%llu\n", val);
-}
-
-static ssize_t mdio_bus_device_stat_field_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct mdio_bus_stat_attr *sattr = to_sattr(attr);
- struct mdio_device *mdiodev = to_mdio_device(dev);
- struct mii_bus *bus = mdiodev->bus;
- int addr = mdiodev->addr;
- u64 val;
-
- val = mdio_bus_get_stat(&bus->stats[addr], sattr->field_offset);
-
- return sysfs_emit(buf, "%llu\n", val);
-}
-
-#define MDIO_BUS_STATS_ATTR(field) \
-static const struct mdio_bus_stat_attr dev_attr_mdio_bus_##field = { \
- .attr = __ATTR(field, 0444, mdio_bus_stat_field_show, NULL), \
- .address = -1, \
- .field_offset = offsetof(struct mdio_bus_stats, field), \
-}; \
-static const struct mdio_bus_stat_attr dev_attr_mdio_bus_device_##field = { \
- .attr = __ATTR(field, 0444, mdio_bus_device_stat_field_show, NULL), \
- .field_offset = offsetof(struct mdio_bus_stats, field), \
-}
-
-MDIO_BUS_STATS_ATTR(transfers);
-MDIO_BUS_STATS_ATTR(errors);
-MDIO_BUS_STATS_ATTR(writes);
-MDIO_BUS_STATS_ATTR(reads);
-
-#define MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, file) \
-static const struct mdio_bus_stat_attr \
-dev_attr_mdio_bus_addr_##field##_##addr = { \
- .attr = { .attr = { .name = file, .mode = 0444 }, \
- .show = mdio_bus_stat_field_show, \
- }, \
- .address = addr, \
- .field_offset = offsetof(struct mdio_bus_stats, field), \
-}
-
-#define MDIO_BUS_STATS_ADDR_ATTR(field, addr) \
- MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, \
- __stringify(field) "_" __stringify(addr))
-
-#define MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(addr) \
- MDIO_BUS_STATS_ADDR_ATTR(transfers, addr); \
- MDIO_BUS_STATS_ADDR_ATTR(errors, addr); \
- MDIO_BUS_STATS_ADDR_ATTR(writes, addr); \
- MDIO_BUS_STATS_ADDR_ATTR(reads, addr) \
-
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(0);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(1);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(2);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(3);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(4);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(5);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(6);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(7);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(8);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(9);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(10);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(11);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(12);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(13);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(14);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(15);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(16);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(17);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(18);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(19);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(20);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(21);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(22);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(23);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(24);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(25);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(26);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(27);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(28);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(29);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(30);
-MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(31);
-
-#define MDIO_BUS_STATS_ADDR_ATTR_GROUP(addr) \
- &dev_attr_mdio_bus_addr_transfers_##addr.attr.attr, \
- &dev_attr_mdio_bus_addr_errors_##addr.attr.attr, \
- &dev_attr_mdio_bus_addr_writes_##addr.attr.attr, \
- &dev_attr_mdio_bus_addr_reads_##addr.attr.attr \
-
-static const struct attribute *const mdio_bus_statistics_attrs[] = {
- &dev_attr_mdio_bus_transfers.attr.attr,
- &dev_attr_mdio_bus_errors.attr.attr,
- &dev_attr_mdio_bus_writes.attr.attr,
- &dev_attr_mdio_bus_reads.attr.attr,
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(0),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(1),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(2),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(3),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(4),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(5),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(6),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(7),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(8),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(9),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(10),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(11),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(12),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(13),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(14),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(15),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(16),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(17),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(18),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(19),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(20),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(21),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(22),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(23),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(24),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(25),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(26),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(27),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(28),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(29),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(30),
- MDIO_BUS_STATS_ADDR_ATTR_GROUP(31),
- NULL,
-};
-
-static const struct attribute_group mdio_bus_statistics_group = {
- .name = "statistics",
- .attrs_const = mdio_bus_statistics_attrs,
-};
-__ATTRIBUTE_GROUPS(mdio_bus_statistics);
-
-const struct class mdio_bus_class = {
- .name = "mdio_bus",
- .dev_release = mdiobus_release,
- .dev_groups = mdio_bus_statistics_groups,
-};
-EXPORT_SYMBOL_GPL(mdio_bus_class);
-
static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
{
preempt_disable();
@@ -841,69 +623,5 @@ int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
}
EXPORT_SYMBOL_GPL(mdiobus_c45_modify_changed);
-/**
- * mdio_bus_match - determine if given MDIO driver supports the given
- * MDIO device
- * @dev: target MDIO device
- * @drv: given MDIO driver
- *
- * Return: 1 if the driver supports the device, 0 otherwise
- *
- * Description: This may require calling the devices own match function,
- * since different classes of MDIO devices have different match criteria.
- */
-static int mdio_bus_match(struct device *dev, const struct device_driver *drv)
-{
- const struct mdio_driver *mdiodrv = to_mdio_driver(drv);
- struct mdio_device *mdio = to_mdio_device(dev);
-
- /* Both the driver and device must type-match */
- if (!(mdiodrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY) !=
- !(mdio->flags & MDIO_DEVICE_FLAG_PHY))
- return 0;
-
- if (of_driver_match_device(dev, drv))
- return 1;
-
- if (mdio->bus_match)
- return mdio->bus_match(dev, drv);
-
- return 0;
-}
-
-static int mdio_uevent(const struct device *dev, struct kobj_uevent_env *env)
-{
- int rc;
-
- /* Some devices have extra OF data and an OF-style MODALIAS */
- rc = of_device_uevent_modalias(dev, env);
- if (rc != -ENODEV)
- return rc;
-
- return 0;
-}
-
-static const struct attribute *const mdio_bus_device_statistics_attrs[] = {
- &dev_attr_mdio_bus_device_transfers.attr.attr,
- &dev_attr_mdio_bus_device_errors.attr.attr,
- &dev_attr_mdio_bus_device_writes.attr.attr,
- &dev_attr_mdio_bus_device_reads.attr.attr,
- NULL,
-};
-
-static const struct attribute_group mdio_bus_device_statistics_group = {
- .name = "statistics",
- .attrs_const = mdio_bus_device_statistics_attrs,
-};
-__ATTRIBUTE_GROUPS(mdio_bus_device_statistics);
-
-const struct bus_type mdio_bus_type = {
- .name = "mdio_bus",
- .dev_groups = mdio_bus_device_statistics_groups,
- .match = mdio_bus_match,
- .uevent = mdio_uevent,
-};
-EXPORT_SYMBOL(mdio_bus_type);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MDIO bus/device layer");
diff --git a/drivers/net/phy/mdio_bus_provider.c b/drivers/net/phy/mdio_bus_provider.c
index d50fe6eb4b0..041576eba47 100644
--- a/drivers/net/phy/mdio_bus_provider.c
+++ b/drivers/net/phy/mdio_bus_provider.c
@@ -28,6 +28,281 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
+#include "phylib-internal.h"
+
+/**
+ * mdiobus_release - mii_bus device release callback
+ * @d: the target struct device that contains the mii_bus
+ *
+ * Description: called when the last reference to an mii_bus is
+ * dropped, to free the underlying memory.
+ */
+static void mdiobus_release(struct device *d)
+{
+ struct mii_bus *bus = to_mii_bus(d);
+
+ WARN(bus->state != MDIOBUS_RELEASED &&
+ /* for compatibility with error handling in drivers */
+ bus->state != MDIOBUS_ALLOCATED,
+ "%s: not in RELEASED or ALLOCATED state\n",
+ bus->id);
+
+ if (bus->state == MDIOBUS_RELEASED)
+ fwnode_handle_put(dev_fwnode(d));
+
+ kfree(bus);
+}
+
+struct mdio_bus_stat_attr {
+ struct device_attribute attr;
+ int address;
+ unsigned int field_offset;
+};
+
+static struct mdio_bus_stat_attr *to_sattr(struct device_attribute *attr)
+{
+ return container_of(attr, struct mdio_bus_stat_attr, attr);
+}
+
+static u64 mdio_bus_get_stat(struct mdio_bus_stats *s, unsigned int offset)
+{
+ const u64_stats_t *stats = (const void *)s + offset;
+ unsigned int start;
+ u64 val = 0;
+
+ do {
+ start = u64_stats_fetch_begin(&s->syncp);
+ val = u64_stats_read(stats);
+ } while (u64_stats_fetch_retry(&s->syncp, start));
+
+ return val;
+}
+
+static ssize_t mdio_bus_stat_field_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mdio_bus_stat_attr *sattr = to_sattr(attr);
+ struct mii_bus *bus = to_mii_bus(dev);
+ u64 val = 0;
+
+ if (sattr->address < 0) {
+ /* get global stats */
+ for (int i = 0; i < PHY_MAX_ADDR; i++)
+ val += mdio_bus_get_stat(&bus->stats[i],
+ sattr->field_offset);
+ } else {
+ val = mdio_bus_get_stat(&bus->stats[sattr->address],
+ sattr->field_offset);
+ }
+
+ return sysfs_emit(buf, "%llu\n", val);
+}
+
+static ssize_t mdio_bus_device_stat_field_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mdio_bus_stat_attr *sattr = to_sattr(attr);
+ struct mdio_device *mdiodev = to_mdio_device(dev);
+ struct mii_bus *bus = mdiodev->bus;
+ int addr = mdiodev->addr;
+ u64 val;
+
+ val = mdio_bus_get_stat(&bus->stats[addr], sattr->field_offset);
+
+ return sysfs_emit(buf, "%llu\n", val);
+}
+
+#define MDIO_BUS_STATS_ATTR(field) \
+static const struct mdio_bus_stat_attr dev_attr_mdio_bus_##field = { \
+ .attr = __ATTR(field, 0444, mdio_bus_stat_field_show, NULL), \
+ .address = -1, \
+ .field_offset = offsetof(struct mdio_bus_stats, field), \
+}; \
+static const struct mdio_bus_stat_attr dev_attr_mdio_bus_device_##field = { \
+ .attr = __ATTR(field, 0444, mdio_bus_device_stat_field_show, NULL), \
+ .field_offset = offsetof(struct mdio_bus_stats, field), \
+}
+
+MDIO_BUS_STATS_ATTR(transfers);
+MDIO_BUS_STATS_ATTR(errors);
+MDIO_BUS_STATS_ATTR(writes);
+MDIO_BUS_STATS_ATTR(reads);
+
+#define MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, file) \
+static const struct mdio_bus_stat_attr \
+dev_attr_mdio_bus_addr_##field##_##addr = { \
+ .attr = { .attr = { .name = file, .mode = 0444 }, \
+ .show = mdio_bus_stat_field_show, \
+ }, \
+ .address = addr, \
+ .field_offset = offsetof(struct mdio_bus_stats, field), \
+}
+
+#define MDIO_BUS_STATS_ADDR_ATTR(field, addr) \
+ MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, \
+ __stringify(field) "_" __stringify(addr))
+
+#define MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(addr) \
+ MDIO_BUS_STATS_ADDR_ATTR(transfers, addr); \
+ MDIO_BUS_STATS_ADDR_ATTR(errors, addr); \
+ MDIO_BUS_STATS_ADDR_ATTR(writes, addr); \
+ MDIO_BUS_STATS_ADDR_ATTR(reads, addr) \
+
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(0);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(1);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(2);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(3);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(4);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(5);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(6);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(7);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(8);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(9);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(10);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(11);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(12);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(13);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(14);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(15);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(16);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(17);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(18);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(19);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(20);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(21);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(22);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(23);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(24);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(25);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(26);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(27);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(28);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(29);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(30);
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(31);
+
+#define MDIO_BUS_STATS_ADDR_ATTR_GROUP(addr) \
+ &(dev_attr_mdio_bus_addr_transfers_##addr).attr.attr, \
+ &(dev_attr_mdio_bus_addr_errors_##addr).attr.attr, \
+ &(dev_attr_mdio_bus_addr_writes_##addr).attr.attr, \
+ &(dev_attr_mdio_bus_addr_reads_##addr).attr.attr \
+
+static const struct attribute *const mdio_bus_statistics_attrs[] = {
+ &dev_attr_mdio_bus_transfers.attr.attr,
+ &dev_attr_mdio_bus_errors.attr.attr,
+ &dev_attr_mdio_bus_writes.attr.attr,
+ &dev_attr_mdio_bus_reads.attr.attr,
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(0),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(1),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(2),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(3),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(4),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(5),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(6),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(7),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(8),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(9),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(10),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(11),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(12),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(13),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(14),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(15),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(16),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(17),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(18),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(19),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(20),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(21),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(22),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(23),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(24),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(25),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(26),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(27),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(28),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(29),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(30),
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(31),
+ NULL,
+};
+
+static const struct attribute_group mdio_bus_statistics_group = {
+ .name = "statistics",
+ .attrs_const = mdio_bus_statistics_attrs,
+};
+__ATTRIBUTE_GROUPS(mdio_bus_statistics);
+
+const struct class mdio_bus_class = {
+ .name = "mdio_bus",
+ .dev_release = mdiobus_release,
+ .dev_groups = mdio_bus_statistics_groups,
+};
+
+/**
+ * mdio_bus_match - determine if given MDIO driver supports the given
+ * MDIO device
+ * @dev: target MDIO device
+ * @drv: given MDIO driver
+ *
+ * Return: 1 if the driver supports the device, 0 otherwise
+ *
+ * Description: This may require calling the devices own match function,
+ * since different classes of MDIO devices have different match criteria.
+ */
+static int mdio_bus_match(struct device *dev, const struct device_driver *drv)
+{
+ const struct mdio_driver *mdiodrv = to_mdio_driver(drv);
+ struct mdio_device *mdio = to_mdio_device(dev);
+
+ /* Both the driver and device must type-match */
+ if (!(mdiodrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY) !=
+ !(mdio->flags & MDIO_DEVICE_FLAG_PHY))
+ return 0;
+
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
+ if (mdio->bus_match)
+ return mdio->bus_match(dev, drv);
+
+ return 0;
+}
+
+static int mdio_uevent(const struct device *dev, struct kobj_uevent_env *env)
+{
+ int rc;
+
+ /* Some devices have extra OF data and an OF-style MODALIAS */
+ rc = of_device_uevent_modalias(dev, env);
+ if (rc != -ENODEV)
+ return rc;
+
+ return 0;
+}
+
+static const struct attribute *const mdio_bus_device_statistics_attrs[] = {
+ &dev_attr_mdio_bus_device_transfers.attr.attr,
+ &dev_attr_mdio_bus_device_errors.attr.attr,
+ &dev_attr_mdio_bus_device_writes.attr.attr,
+ &dev_attr_mdio_bus_device_reads.attr.attr,
+ NULL,
+};
+
+static const struct attribute_group mdio_bus_device_statistics_group = {
+ .name = "statistics",
+ .attrs_const = mdio_bus_device_statistics_attrs,
+};
+__ATTRIBUTE_GROUPS(mdio_bus_device_statistics);
+
+const struct bus_type mdio_bus_type = {
+ .name = "mdio_bus",
+ .dev_groups = mdio_bus_device_statistics_groups,
+ .match = mdio_bus_match,
+ .uevent = mdio_uevent,
+};
/**
* mdiobus_alloc_size - allocate a mii_bus structure
diff --git a/drivers/net/phy/phylib-internal.h b/drivers/net/phy/phylib-internal.h
index bfb1aa82386..664ed7faa51 100644
--- a/drivers/net/phy/phylib-internal.h
+++ b/drivers/net/phy/phylib-internal.h
@@ -9,6 +9,9 @@
struct mdio_device;
struct phy_device;
+extern const struct bus_type mdio_bus_type;
+extern const struct class mdio_bus_class;
+
/*
* phy_supported_speeds - return all speeds currently supported by a PHY device
*/
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e9b0d7427b0..5de4b172cd0 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -2446,9 +2446,6 @@ int __phy_hwtstamp_set(struct phy_device *phydev,
struct phy_port *phy_get_sfp_port(struct phy_device *phydev);
-extern const struct bus_type mdio_bus_type;
-extern const struct class mdio_bus_class;
-
/**
* phy_module_driver() - Helper macro for registering PHY drivers
* @__phy_drivers: array of PHY drivers to register
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 net-next 4/5] net: phy: move registering mdio_bus_class and mdio_bus_type to libphy
From: Heiner Kallweit @ 2026-03-09 17:04 UTC (permalink / raw)
To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
Jakub Kicinski, David Miller, Eric Dumazet, Bjorn Andersson,
Michael Turquette, Stephen Boyd, Vinod Koul, Neil Armstrong
Cc: netdev@vger.kernel.org, Philipp Zabel, linux-arm-msm, linux-clk,
linux-phy
In-Reply-To: <9d5724bc-e525-4f8f-b3f8-b16dd5a1164e@gmail.com>
The MDIO consumer side shouldn't register class and bus_type.
Therefore move this to libphy.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
drivers/net/phy/mdio_bus.c | 23 -----------------------
drivers/net/phy/phy_device.c | 13 +++++++++++++
2 files changed, 13 insertions(+), 23 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index c9a495390d2..9fb47332602 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -905,28 +905,5 @@ const struct bus_type mdio_bus_type = {
};
EXPORT_SYMBOL(mdio_bus_type);
-static int __init mdio_bus_init(void)
-{
- int ret;
-
- ret = class_register(&mdio_bus_class);
- if (!ret) {
- ret = bus_register(&mdio_bus_type);
- if (ret)
- class_unregister(&mdio_bus_class);
- }
-
- return ret;
-}
-
-static void __exit mdio_bus_exit(void)
-{
- class_unregister(&mdio_bus_class);
- bus_unregister(&mdio_bus_type);
-}
-
-subsys_initcall(mdio_bus_init);
-module_exit(mdio_bus_exit);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MDIO bus/device layer");
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index d1cbcfc3d2a..0edff47478c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3913,6 +3913,14 @@ static int __init phy_init(void)
{
int rc;
+ rc = class_register(&mdio_bus_class);
+ if (rc)
+ return rc;
+
+ rc = bus_register(&mdio_bus_type);
+ if (rc)
+ goto err_class;
+
rtnl_lock();
ethtool_set_ethtool_phy_ops(&phy_ethtool_phy_ops);
phylib_register_stubs();
@@ -3941,6 +3949,9 @@ static int __init phy_init(void)
phylib_unregister_stubs();
ethtool_set_ethtool_phy_ops(NULL);
rtnl_unlock();
+ bus_unregister(&mdio_bus_type);
+err_class:
+ class_unregister(&mdio_bus_class);
return rc;
}
@@ -3953,6 +3964,8 @@ static void __exit phy_exit(void)
phylib_unregister_stubs();
ethtool_set_ethtool_phy_ops(NULL);
rtnl_unlock();
+ bus_unregister(&mdio_bus_type);
+ class_unregister(&mdio_bus_class);
}
subsys_initcall(phy_init);
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 net-next 3/5] net: phy: move (of_)mdio_find_bus to mdio_bus_provider.c
From: Heiner Kallweit @ 2026-03-09 17:04 UTC (permalink / raw)
To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
Jakub Kicinski, David Miller, Eric Dumazet, Bjorn Andersson,
Michael Turquette, Stephen Boyd, Vinod Koul, Neil Armstrong
Cc: netdev@vger.kernel.org, Philipp Zabel, linux-arm-msm, linux-clk,
linux-phy
In-Reply-To: <9d5724bc-e525-4f8f-b3f8-b16dd5a1164e@gmail.com>
Functionality outside libphy shouldn't access mdio_bus_class directly.
So move both functions to the provider side. This is a step towards
making mdio_bus_class private to libphy.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
drivers/net/phy/mdio_bus.c | 44 -----------------------------
drivers/net/phy/mdio_bus_provider.c | 44 +++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index a30c679feec..c9a495390d2 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -276,50 +276,6 @@ const struct class mdio_bus_class = {
};
EXPORT_SYMBOL_GPL(mdio_bus_class);
-/**
- * mdio_find_bus - Given the name of a mdiobus, find the mii_bus.
- * @mdio_name: The name of a mdiobus.
- *
- * Return: a reference to the mii_bus, or NULL if none found. The
- * embedded struct device will have its reference count incremented,
- * and this must be put_deviced'ed once the bus is finished with.
- */
-struct mii_bus *mdio_find_bus(const char *mdio_name)
-{
- struct device *d;
-
- d = class_find_device_by_name(&mdio_bus_class, mdio_name);
- return d ? to_mii_bus(d) : NULL;
-}
-EXPORT_SYMBOL(mdio_find_bus);
-
-#if IS_ENABLED(CONFIG_OF_MDIO)
-/**
- * of_mdio_find_bus - Given an mii_bus node, find the mii_bus.
- * @mdio_bus_np: Pointer to the mii_bus.
- *
- * Return: a reference to the mii_bus, or NULL if none found. The
- * embedded struct device will have its reference count incremented,
- * and this must be put once the bus is finished with.
- *
- * Because the association of a device_node and mii_bus is made via
- * of_mdiobus_register(), the mii_bus cannot be found before it is
- * registered with of_mdiobus_register().
- *
- */
-struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np)
-{
- struct device *d;
-
- if (!mdio_bus_np)
- return NULL;
-
- d = class_find_device_by_of_node(&mdio_bus_class, mdio_bus_np);
- return d ? to_mii_bus(d) : NULL;
-}
-EXPORT_SYMBOL(of_mdio_find_bus);
-#endif
-
static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
{
preempt_disable();
diff --git a/drivers/net/phy/mdio_bus_provider.c b/drivers/net/phy/mdio_bus_provider.c
index 4b063740574..d50fe6eb4b0 100644
--- a/drivers/net/phy/mdio_bus_provider.c
+++ b/drivers/net/phy/mdio_bus_provider.c
@@ -440,3 +440,47 @@ void mdiobus_free(struct mii_bus *bus)
put_device(&bus->dev);
}
EXPORT_SYMBOL(mdiobus_free);
+
+/**
+ * mdio_find_bus - Given the name of a mdiobus, find the mii_bus.
+ * @mdio_name: The name of a mdiobus.
+ *
+ * Return: a reference to the mii_bus, or NULL if none found. The
+ * embedded struct device will have its reference count incremented,
+ * and this must be put_deviced'ed once the bus is finished with.
+ */
+struct mii_bus *mdio_find_bus(const char *mdio_name)
+{
+ struct device *d;
+
+ d = class_find_device_by_name(&mdio_bus_class, mdio_name);
+ return d ? to_mii_bus(d) : NULL;
+}
+EXPORT_SYMBOL(mdio_find_bus);
+
+#if IS_ENABLED(CONFIG_OF_MDIO)
+/**
+ * of_mdio_find_bus - Given an mii_bus node, find the mii_bus.
+ * @mdio_bus_np: Pointer to the mii_bus.
+ *
+ * Return: a reference to the mii_bus, or NULL if none found. The
+ * embedded struct device will have its reference count incremented,
+ * and this must be put once the bus is finished with.
+ *
+ * Because the association of a device_node and mii_bus is made via
+ * of_mdiobus_register(), the mii_bus cannot be found before it is
+ * registered with of_mdiobus_register().
+ *
+ */
+struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np)
+{
+ struct device *d;
+
+ if (!mdio_bus_np)
+ return NULL;
+
+ d = class_find_device_by_of_node(&mdio_bus_class, mdio_bus_np);
+ return d ? to_mii_bus(d) : NULL;
+}
+EXPORT_SYMBOL(of_mdio_find_bus);
+#endif
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 net-next 2/5] net: phy: make mdio_device.c part of libphy
From: Heiner Kallweit @ 2026-03-09 17:03 UTC (permalink / raw)
To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
Jakub Kicinski, David Miller, Eric Dumazet, Bjorn Andersson,
Michael Turquette, Stephen Boyd, Vinod Koul, Neil Armstrong
Cc: netdev@vger.kernel.org, Philipp Zabel, linux-arm-msm, linux-clk,
linux-phy
In-Reply-To: <9d5724bc-e525-4f8f-b3f8-b16dd5a1164e@gmail.com>
This patch
- makes mdio_device.c part of libphy
- makes mdio_device_(un)register_reset() static
- moves mdiobus_(un)register_device() from mdio_bus.c to mdio_device.c,
stops exporting both functions and makes them private to phylib
This further decouples the MDIO consumer functionality from libphy.
Note: This makes MDIO driver registration part of phylib, therefore
adjust Kconfig dependencies where needed.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- add needed Kconfig dependency changes
---
drivers/clk/qcom/Kconfig | 2 +-
drivers/net/phy/Makefile | 6 ++---
drivers/net/phy/mdio-private.h | 11 ---------
drivers/net/phy/mdio_bus.c | 36 ----------------------------
drivers/net/phy/mdio_device.c | 39 ++++++++++++++++++++++++++++---
drivers/net/phy/phylib-internal.h | 4 ++++
drivers/phy/broadcom/Kconfig | 4 ++--
include/linux/mdio.h | 2 --
8 files changed, 46 insertions(+), 58 deletions(-)
delete mode 100644 drivers/net/phy/mdio-private.h
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index a8a86ea6bb7..a277c434d64 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -392,7 +392,7 @@ config IPQ_NSSCC_9574
config IPQ_NSSCC_QCA8K
tristate "QCA8K(QCA8386 or QCA8084) NSS Clock Controller"
- depends on MDIO_BUS
+ depends on PHYLIB
help
Support for NSS(Network SubSystem) clock controller on
qca8386/qca8084 chip.
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3a34917adea..8d262b4e2be 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -3,8 +3,8 @@
libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \
linkmode.o phy_link_topology.o \
- phy_caps.o mdio_bus_provider.o phy_port.o
-mdio-bus-y += mdio_bus.o mdio_device.o
+ phy_caps.o mdio_bus_provider.o phy_port.o \
+ mdio_device.o
ifdef CONFIG_PHYLIB
# built-in whenever PHYLIB is built-in or module
@@ -15,7 +15,7 @@ libphy-$(CONFIG_SWPHY) += swphy.o
libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o
libphy-$(CONFIG_OPEN_ALLIANCE_HELPERS) += open_alliance_helpers.o
-obj-$(CONFIG_MDIO_BUS) += mdio-bus.o
+obj-$(CONFIG_MDIO_BUS) += mdio_bus.o
obj-$(CONFIG_PHYLINK) += phylink.o
obj-$(CONFIG_PHYLIB) += libphy.o
obj-$(CONFIG_PHYLIB) += mdio_devres.o
diff --git a/drivers/net/phy/mdio-private.h b/drivers/net/phy/mdio-private.h
deleted file mode 100644
index 8bc6d9088af..00000000000
--- a/drivers/net/phy/mdio-private.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-#ifndef __MDIO_PRIVATE_H
-#define __MDIO_PRIVATE_H
-
-/* MDIO internal helpers
- */
-
-int mdio_device_register_reset(struct mdio_device *mdiodev);
-void mdio_device_unregister_reset(struct mdio_device *mdiodev);
-
-#endif /* __MDIO_PRIVATE_H */
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 48c0447e6a8..a30c679feec 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -29,46 +29,10 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
-#include "mdio-private.h"
#define CREATE_TRACE_POINTS
#include <trace/events/mdio.h>
-int mdiobus_register_device(struct mdio_device *mdiodev)
-{
- int err;
-
- if (mdiodev->bus->mdio_map[mdiodev->addr])
- return -EBUSY;
-
- if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) {
- err = mdio_device_register_reset(mdiodev);
- if (err)
- return err;
-
- /* Assert the reset signal */
- mdio_device_reset(mdiodev, 1);
- }
-
- mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;
-
- return 0;
-}
-EXPORT_SYMBOL(mdiobus_register_device);
-
-int mdiobus_unregister_device(struct mdio_device *mdiodev)
-{
- if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
- return -EINVAL;
-
- mdio_device_unregister_reset(mdiodev);
-
- mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL(mdiobus_unregister_device);
-
static struct mdio_device *mdiobus_find_device(struct mii_bus *bus, int addr)
{
bool addr_valid = addr >= 0 && addr < ARRAY_SIZE(bus->mdio_map);
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index da4fb7484c7..56080d3d2d2 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -22,7 +22,7 @@
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/property.h>
-#include "mdio-private.h"
+#include "phylib-internal.h"
/**
* mdio_device_register_reset - Read and initialize the reset properties of
@@ -31,7 +31,7 @@
*
* Return: Zero if successful, negative error code on failure
*/
-int mdio_device_register_reset(struct mdio_device *mdiodev)
+static int mdio_device_register_reset(struct mdio_device *mdiodev)
{
struct reset_control *reset;
@@ -67,7 +67,7 @@ int mdio_device_register_reset(struct mdio_device *mdiodev)
* an mdio device
* @mdiodev: mdio_device structure
*/
-void mdio_device_unregister_reset(struct mdio_device *mdiodev)
+static void mdio_device_unregister_reset(struct mdio_device *mdiodev)
{
gpiod_put(mdiodev->reset_gpio);
mdiodev->reset_gpio = NULL;
@@ -189,6 +189,39 @@ void mdio_device_remove(struct mdio_device *mdiodev)
}
EXPORT_SYMBOL(mdio_device_remove);
+int mdiobus_register_device(struct mdio_device *mdiodev)
+{
+ int err;
+
+ if (mdiodev->bus->mdio_map[mdiodev->addr])
+ return -EBUSY;
+
+ if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) {
+ err = mdio_device_register_reset(mdiodev);
+ if (err)
+ return err;
+
+ /* Assert the reset signal */
+ mdio_device_reset(mdiodev, 1);
+ }
+
+ mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;
+
+ return 0;
+}
+
+int mdiobus_unregister_device(struct mdio_device *mdiodev)
+{
+ if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
+ return -EINVAL;
+
+ mdio_device_unregister_reset(mdiodev);
+
+ mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
+
+ return 0;
+}
+
/**
* mdio_probe - probe an MDIO device
* @dev: device to probe
diff --git a/drivers/net/phy/phylib-internal.h b/drivers/net/phy/phylib-internal.h
index dc9592c6bb8..bfb1aa82386 100644
--- a/drivers/net/phy/phylib-internal.h
+++ b/drivers/net/phy/phylib-internal.h
@@ -6,6 +6,7 @@
#ifndef __PHYLIB_INTERNAL_H
#define __PHYLIB_INTERNAL_H
+struct mdio_device;
struct phy_device;
/*
@@ -20,6 +21,9 @@ void of_set_phy_timing_role(struct phy_device *phydev);
int phy_speed_down_core(struct phy_device *phydev);
void phy_check_downshift(struct phy_device *phydev);
+int mdiobus_register_device(struct mdio_device *mdiodev);
+int mdiobus_unregister_device(struct mdio_device *mdiodev);
+
int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv);
#endif /* __PHYLIB_INTERNAL_H */
diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig
index 1d89a2fd9b7..46371a8940d 100644
--- a/drivers/phy/broadcom/Kconfig
+++ b/drivers/phy/broadcom/Kconfig
@@ -52,7 +52,7 @@ config PHY_BCM_NS_USB3
tristate "Broadcom Northstar USB 3.0 PHY Driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on HAS_IOMEM && OF
- depends on MDIO_BUS
+ depends on PHYLIB
select GENERIC_PHY
help
Enable this to support Broadcom USB 3.0 PHY connected to the USB
@@ -60,7 +60,7 @@ config PHY_BCM_NS_USB3
config PHY_NS2_PCIE
tristate "Broadcom Northstar2 PCIe PHY driver"
- depends on (OF && MDIO_BUS_MUX_BCM_IPROC) || (COMPILE_TEST && MDIO_BUS)
+ depends on (OF && MDIO_BUS_MUX_BCM_IPROC) || (COMPILE_TEST && PHYLIB)
select GENERIC_PHY
default ARCH_BCM_IPROC
help
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index 5d1203b9af2..f4f9d960944 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -688,8 +688,6 @@ static inline int mdiodev_c45_write(struct mdio_device *mdiodev, u32 devad,
val);
}
-int mdiobus_register_device(struct mdio_device *mdiodev);
-int mdiobus_unregister_device(struct mdio_device *mdiodev);
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr);
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 net-next 1/5] net: phy: move mdio_device reset handling functions in the code
From: Heiner Kallweit @ 2026-03-09 17:02 UTC (permalink / raw)
To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
Jakub Kicinski, David Miller, Eric Dumazet, Bjorn Andersson,
Michael Turquette, Stephen Boyd, Vinod Koul, Neil Armstrong
Cc: netdev@vger.kernel.org, Philipp Zabel, linux-arm-msm, linux-clk,
linux-phy
In-Reply-To: <9d5724bc-e525-4f8f-b3f8-b16dd5a1164e@gmail.com>
In preparation of a follow-up patch this moves reset-related functions
in the code.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
drivers/net/phy/mdio_device.c | 162 +++++++++++++++++-----------------
1 file changed, 81 insertions(+), 81 deletions(-)
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index b8a5a183819..da4fb7484c7 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -24,6 +24,87 @@
#include <linux/property.h>
#include "mdio-private.h"
+/**
+ * mdio_device_register_reset - Read and initialize the reset properties of
+ * an mdio device
+ * @mdiodev: mdio_device structure
+ *
+ * Return: Zero if successful, negative error code on failure
+ */
+int mdio_device_register_reset(struct mdio_device *mdiodev)
+{
+ struct reset_control *reset;
+
+ /* Deassert the optional reset signal */
+ mdiodev->reset_gpio = gpiod_get_optional(&mdiodev->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(mdiodev->reset_gpio))
+ return PTR_ERR(mdiodev->reset_gpio);
+
+ if (mdiodev->reset_gpio)
+ gpiod_set_consumer_name(mdiodev->reset_gpio, "PHY reset");
+
+ reset = reset_control_get_optional_exclusive(&mdiodev->dev, "phy");
+ if (IS_ERR(reset)) {
+ gpiod_put(mdiodev->reset_gpio);
+ mdiodev->reset_gpio = NULL;
+ return PTR_ERR(reset);
+ }
+
+ mdiodev->reset_ctrl = reset;
+
+ /* Read optional firmware properties */
+ device_property_read_u32(&mdiodev->dev, "reset-assert-us",
+ &mdiodev->reset_assert_delay);
+ device_property_read_u32(&mdiodev->dev, "reset-deassert-us",
+ &mdiodev->reset_deassert_delay);
+
+ return 0;
+}
+
+/**
+ * mdio_device_unregister_reset - uninitialize the reset properties of
+ * an mdio device
+ * @mdiodev: mdio_device structure
+ */
+void mdio_device_unregister_reset(struct mdio_device *mdiodev)
+{
+ gpiod_put(mdiodev->reset_gpio);
+ mdiodev->reset_gpio = NULL;
+ reset_control_put(mdiodev->reset_ctrl);
+ mdiodev->reset_ctrl = NULL;
+ mdiodev->reset_assert_delay = 0;
+ mdiodev->reset_deassert_delay = 0;
+}
+
+void mdio_device_reset(struct mdio_device *mdiodev, int value)
+{
+ unsigned int d;
+
+ if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl)
+ return;
+
+ if (mdiodev->reset_state == value)
+ return;
+
+ if (mdiodev->reset_gpio)
+ gpiod_set_value_cansleep(mdiodev->reset_gpio, value);
+
+ if (mdiodev->reset_ctrl) {
+ if (value)
+ reset_control_assert(mdiodev->reset_ctrl);
+ else
+ reset_control_deassert(mdiodev->reset_ctrl);
+ }
+
+ d = value ? mdiodev->reset_assert_delay : mdiodev->reset_deassert_delay;
+ if (d)
+ fsleep(d);
+
+ mdiodev->reset_state = value;
+}
+EXPORT_SYMBOL(mdio_device_reset);
+
void mdio_device_free(struct mdio_device *mdiodev)
{
put_device(&mdiodev->dev);
@@ -108,87 +189,6 @@ void mdio_device_remove(struct mdio_device *mdiodev)
}
EXPORT_SYMBOL(mdio_device_remove);
-/**
- * mdio_device_register_reset - Read and initialize the reset properties of
- * an mdio device
- * @mdiodev: mdio_device structure
- *
- * Return: Zero if successful, negative error code on failure
- */
-int mdio_device_register_reset(struct mdio_device *mdiodev)
-{
- struct reset_control *reset;
-
- /* Deassert the optional reset signal */
- mdiodev->reset_gpio = gpiod_get_optional(&mdiodev->dev,
- "reset", GPIOD_OUT_LOW);
- if (IS_ERR(mdiodev->reset_gpio))
- return PTR_ERR(mdiodev->reset_gpio);
-
- if (mdiodev->reset_gpio)
- gpiod_set_consumer_name(mdiodev->reset_gpio, "PHY reset");
-
- reset = reset_control_get_optional_exclusive(&mdiodev->dev, "phy");
- if (IS_ERR(reset)) {
- gpiod_put(mdiodev->reset_gpio);
- mdiodev->reset_gpio = NULL;
- return PTR_ERR(reset);
- }
-
- mdiodev->reset_ctrl = reset;
-
- /* Read optional firmware properties */
- device_property_read_u32(&mdiodev->dev, "reset-assert-us",
- &mdiodev->reset_assert_delay);
- device_property_read_u32(&mdiodev->dev, "reset-deassert-us",
- &mdiodev->reset_deassert_delay);
-
- return 0;
-}
-
-/**
- * mdio_device_unregister_reset - uninitialize the reset properties of
- * an mdio device
- * @mdiodev: mdio_device structure
- */
-void mdio_device_unregister_reset(struct mdio_device *mdiodev)
-{
- gpiod_put(mdiodev->reset_gpio);
- mdiodev->reset_gpio = NULL;
- reset_control_put(mdiodev->reset_ctrl);
- mdiodev->reset_ctrl = NULL;
- mdiodev->reset_assert_delay = 0;
- mdiodev->reset_deassert_delay = 0;
-}
-
-void mdio_device_reset(struct mdio_device *mdiodev, int value)
-{
- unsigned int d;
-
- if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl)
- return;
-
- if (mdiodev->reset_state == value)
- return;
-
- if (mdiodev->reset_gpio)
- gpiod_set_value_cansleep(mdiodev->reset_gpio, value);
-
- if (mdiodev->reset_ctrl) {
- if (value)
- reset_control_assert(mdiodev->reset_ctrl);
- else
- reset_control_deassert(mdiodev->reset_ctrl);
- }
-
- d = value ? mdiodev->reset_assert_delay : mdiodev->reset_deassert_delay;
- if (d)
- fsleep(d);
-
- mdiodev->reset_state = value;
-}
-EXPORT_SYMBOL(mdio_device_reset);
-
/**
* mdio_probe - probe an MDIO device
* @dev: device to probe
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 net-next 0/5] net: phy: further decouple provider from consumer part
From: Heiner Kallweit @ 2026-03-09 17:01 UTC (permalink / raw)
To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
Jakub Kicinski, David Miller, Eric Dumazet, Bjorn Andersson,
Michael Turquette, Stephen Boyd, Vinod Koul, Neil Armstrong
Cc: netdev@vger.kernel.org, Philipp Zabel, linux-arm-msm, linux-clk,
linux-phy
This series aims at further decoupling the provider and consumer part
in phylib.
v2:
- patch 2: add needed Kconfig dependency changes
- patch 5: explain false positive checkpatch error
Heiner Kallweit (5):
net: phy: move mdio_device reset handling functions in the code
net: phy: make mdio_device.c part of libphy
net: phy: move (of_)mdio_find_bus to mdio_bus_provider.c
net: phy: move registering mdio_bus_class and mdio_bus_type to libphy
net: phy: move remaining provider code to mdio_bus_provider.c
drivers/clk/qcom/Kconfig | 2 +-
drivers/net/phy/Makefile | 6 +-
drivers/net/phy/mdio-private.h | 11 -
drivers/net/phy/mdio_bus.c | 385 ----------------------------
drivers/net/phy/mdio_bus_provider.c | 319 +++++++++++++++++++++++
drivers/net/phy/mdio_device.c | 165 +++++++-----
drivers/net/phy/phy_device.c | 13 +
drivers/net/phy/phylib-internal.h | 7 +
drivers/phy/broadcom/Kconfig | 4 +-
include/linux/mdio.h | 2 -
include/linux/phy.h | 3 -
11 files changed, 444 insertions(+), 473 deletions(-)
delete mode 100644 drivers/net/phy/mdio-private.h
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH RESEND2 net-next 0/8] net: stmmac: qcom-ethqos: further serdes reorganisation
From: Vladimir Oltean @ 2026-03-09 15:44 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Russell King (Oracle), Andrew Lunn, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet, linux-arm-kernel, linux-arm-msm,
linux-phy, linux-stm32, Mohd Ayaan Anwar, Neil Armstrong, netdev,
Paolo Abeni, Vinod Koul
In-Reply-To: <20260302155736.1fd2980e@kernel.org>
On Mon, Mar 02, 2026 at 03:57:36PM -0800, Jakub Kicinski wrote:
> Alright, I think the best we can do here is to merge patch 2
> in a "stable tag" way. The rest will have to go via net-next.
>
> I applied patch 2, Russell please rebase the rest on net-next
> and repost. Patch 2 should disappear. I don't want to merge it
> now as is without an explicit nod from Vinod. He did ask for
> a tag and we won't provide one.
>
> Vinod / Vladimir, to merge the "stable tag" of patch 2:
>
> tag_name=phy-qcom-sgmii-eth-add-set_mode-and-validate-methods
> git fetch https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
> git tag $tag_name 0e8147f4da00
> git merge $tag_name
> git tag -d $tag_name
>
> I think this should work.
Thanks for the anonymous tag. I think you mean sha1sum
4ff5801f45b494ad8251a16ec06c9f303ed3b9a0, not 0e8147f4da00.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v11 0/9] mmc: host: renesas_sdhi_core: support configuring an optional sdio mux
From: Ulf Hansson @ 2026-03-09 15:06 UTC (permalink / raw)
To: Josua Mayer, Peter Rosin
Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
Tony Lindgren, Janusz Krzysztofik, Vignesh R, Andi Shyti,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Yoshihiro Shimoda,
Yazan Shhady, Jon Nettleton, Vladimir Oltean, Mikhail Anikin,
linux-can, linux-phy, linux-kernel, linux-omap, linux-i2c,
linux-mmc, devicetree, linux-renesas-soc
In-Reply-To: <CAPDyKFr5NZKEKpV2+GXGnzH9pyyj_TLmMCc3rac8h248srX_dw@mail.gmail.com>
On Thu, 5 Mar 2026 at 17:19, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> On Thu, 26 Feb 2026 at 14:21, Josua Mayer <josua@solid-run.com> wrote:
> >
> > This series has evolved over time from adding generic mux support for
> > renesas sdhi driver, to partial rewrite of the mux framework.
> >
> > Several drivers have started implementing driver-local managed and
> > unmanaged helper functions for getting and selecting a mux-state object.
> >
> > mmc maintainers have requested that new code shall intreoduce and use
> > generic helper functions that can be shared by all drivers, avoiding
> > code duplication.
> >
> > This series is structured in 5 parts, each of which is self-sufficient
> > depending only on the previous patches. This shall allow the first N
> > patches to be applied even if the last ones need further discussion.
> >
> > 1. Rename driver-local helper functions to avoid name collision with
> > global version to be introduced later.
> >
> > 2. Implement generic device-managed helper functions in mux core.
> >
> > 3. Convert driver local code from similar patterns to use the newly
> > added global helpers.
> >
> > 4. Change mux-core Kconfig so that it can be enabled through menuconfig,
> > without an explicit "select" dependency from other drivers.
> >
> > 5. add dt bindings and driver support for mux in renesas sdhi driver.
> >
> > Signed-off-by: Josua Mayer <josua@solid-run.com>
> > ---
> > Changes in v11:
> > - changed approach to Kconfig making MULTIPLEXER a bool, and adding a
> > user-visible wrapper for menuconfig.
> > (Reported-by: Ulf Hansson <ulf.hansson@linaro.org>)
> > - dropped the "default m if COMPILE_TEST".
> > (Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>)
> > - improved kerneldoc line wrapping.
> > - removed unnecessary changes to original devm_mux_control-get.
> > - fix "reference preceded by free" in mux_state_get function
> > - Link to v10: https://lore.kernel.org/r/20260225-rz-sdio-mux-v10-0-1ee44f2ea112@solid-run.com
> >
>
> [...]
>
> To me, this looks ready for a new try. Unless I hear some objections,
> I intend to apply this as material for v7.1 via my mmc tree on Monday.
>
> The complete series will be available on an immutable branch, for
> other subsystem maintainers to pull in if that turns out to be needed.
> I let you know of more details on Monday.
I have now queued up this series for v7.1 via my next branch.
The series is also available at the immutable "mux" branch (based on
v7.0-rc1) via my mmc tree, which other subsystem maintainers can pull
in if needed.
Kind regards
Uffe
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v4 1/3] arm: dts: ti: omap: align node patterns with established convention
From: Charan Pedumuru @ 2026-03-09 14:55 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Kishon Vijay Abraham I, Aaro Koskinen,
Andreas Kemnade, Kevin Hilman, Roger Quadros, Tony Lindgren,
Roger Quadros
Cc: linux-phy, devicetree, linux-kernel, linux-omap
In-Reply-To: <20260123-ti-phy-v4-1-b557e2c46e6f@gmail.com>
Hi,
This patch from this series is still not yet picked to apply.
The dtb_check will throw errors to the YAMLs in this series if this clean up patch is not applied.
On 23-01-2026 21:09, Charan Pedumuru wrote:
> Update OMAP DTS node patterns to match established conventions.
>
> Signed-off-by: Charan Pedumuru <charan.pedumuru@gmail.com>
> ---
> arch/arm/boot/dts/ti/omap/dra7-l4.dtsi | 4 ++--
> arch/arm/boot/dts/ti/omap/omap4-l4.dtsi | 4 ++--
> arch/arm/boot/dts/ti/omap/omap5-l4.dtsi | 2 +-
> 3 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
> index c9282f57ffa5..ed206eb84d02 100644
> --- a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
> +++ b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
> @@ -328,7 +328,7 @@ ocp2scp@0 {
> ranges = <0 0 0x8000>;
> reg = <0x0 0x20>;
>
> - pcie1_phy: pciephy@4000 {
> + pcie1_phy: pcie-phy@4000 {
> compatible = "ti,phy-pipe3-pcie";
> reg = <0x4000 0x80>, /* phy_rx */
> <0x4400 0x64>; /* phy_tx */
> @@ -348,7 +348,7 @@ pcie1_phy: pciephy@4000 {
> #phy-cells = <0>;
> };
>
> - pcie2_phy: pciephy@5000 {
> + pcie2_phy: pcie-phy@5000 {
> compatible = "ti,phy-pipe3-pcie";
> reg = <0x5000 0x80>, /* phy_rx */
> <0x5400 0x64>; /* phy_tx */
> diff --git a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
> index 4ee53dfb71b4..d8b16cbe6c35 100644
> --- a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
> +++ b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
> @@ -72,13 +72,13 @@ scm_conf: scm_conf@0 {
> #size-cells = <1>;
> };
>
> - omap_control_usb2phy: control-phy@300 {
> + omap_control_usb2phy: phy@300 {
> compatible = "ti,control-phy-usb2";
> reg = <0x300 0x4>;
> reg-names = "power";
> };
>
> - omap_control_usbotg: control-phy@33c {
> + omap_control_usbotg: phy@33c {
> compatible = "ti,control-phy-otghs";
> reg = <0x33c 0x4>;
> reg-names = "otghs_control";
> diff --git a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
> index 9f6100c7c34d..5c94db589dd1 100644
> --- a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
> +++ b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
> @@ -472,7 +472,7 @@ usb2_phy: usb2phy@4000 {
> #phy-cells = <0>;
> };
>
> - usb3_phy: usb3phy@4400 {
> + usb3_phy: usb3-phy@4400 {
> compatible = "ti,omap-usb3";
> reg = <0x4400 0x80>,
> <0x4800 0x64>,
>
--
Best Regards,
Charan.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v9] phy: Add driver for EyeQ5 Ethernet PHY wrapper
From: Théo Lebrun @ 2026-03-09 14:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: linux-phy, linux-kernel, linux-mips, Vladimir Kondratiev,
Gregory CLEMENT, Benoît Monin, Tawfik Bayouk,
Thomas Petazzoni, Luca Ceresoli, Théo Lebrun
In-Reply-To: <20260309-macb-phy-v9-0-5afd87d9db43@bootlin.com>
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@bootlin.com>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
MAINTAINERS | 1 +
drivers/phy/Kconfig | 13 ++
drivers/phy/Makefile | 1 +
drivers/phy/phy-eyeq5-eth.c | 280 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 295 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 55af015174a5..6bc2ae3bbd4b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17812,6 +17812,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 3970aa1f300f..cb973a5c0d28 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -67,6 +67,19 @@ config PHY_CAN_TRANSCEIVER
functional modes using gpios and sets the attribute max link
rate, for CAN drivers.
+config PHY_EYEQ5_ETH
+ tristate "Ethernet PHY Driver on EyeQ5"
+ depends on OF
+ depends on MACH_EYEQ5 || COMPILE_TEST
+ select AUXILIARY_BUS
+ select GENERIC_PHY
+ default MACH_EYEQ5
+ 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.
+
config PHY_GOOGLE_USB
tristate "Google Tensor SoC USB PHY driver"
select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f49d83f00a3d..05be5759cd10 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
+obj-$(CONFIG_PHY_EYEQ5_ETH) += phy-eyeq5-eth.o
obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
diff --git a/drivers/phy/phy-eyeq5-eth.c b/drivers/phy/phy-eyeq5-eth.c
new file mode 100644
index 000000000000..c03d77c360f7
--- /dev/null
+++ b/drivers/phy/phy-eyeq5-eth.c
@@ -0,0 +1,280 @@
+// 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)
+
+/*
+ * Instead of storing a phy_interface_t, we store this enum.
+ *
+ * We do not deal with RGMII timings in this generic PHY driver,
+ * it is all handled inside the net PHY.
+ */
+enum eq5_phy_submode {
+ EQ5_PHY_SUBMODE_SGMII,
+ EQ5_PHY_SUBMODE_RGMII,
+};
+
+struct eq5_phy_inst {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *gp, *sgmii;
+ enum eq5_phy_submode submode;
+ bool sgmii_support;
+};
+
+struct eq5_phy_private {
+ struct eq5_phy_inst phys[EQ5_PHY_COUNT];
+};
+
+static int eq5_phy_exit(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+
+ writel(0, inst->gp);
+ writel(0, inst->sgmii);
+ udelay(5); /* settling time */
+ return 0;
+}
+
+static int eq5_phy_init(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ u32 reg;
+
+ /*
+ * Hardware stops listening to our instructions once it is started.
+ * It must be reset to reconfigure it.
+ */
+ eq5_phy_exit(phy);
+
+ reg = 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_power_on(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ u32 reg;
+
+ if (inst->submode == EQ5_PHY_SUBMODE_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(inst->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);
+
+ writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp);
+ writel(0, inst->sgmii);
+
+ return 0;
+}
+
+static int eq5_phy_validate(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+
+ if (mode != PHY_MODE_ETHERNET)
+ return -EINVAL;
+
+ if (phy_interface_mode_is_rgmii(submode))
+ return 0;
+
+ if (inst->sgmii_support && submode == PHY_INTERFACE_MODE_SGMII)
+ return 0;
+
+ return -EINVAL;
+}
+
+static int eq5_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ enum eq5_phy_submode target_submode;
+ int ret;
+
+ ret = eq5_phy_validate(phy, mode, submode, NULL);
+ if (ret)
+ return ret;
+
+ if (submode == PHY_INTERFACE_MODE_SGMII)
+ target_submode = EQ5_PHY_SUBMODE_SGMII;
+ else
+ target_submode = EQ5_PHY_SUBMODE_RGMII;
+
+ if (target_submode == inst->submode)
+ return 0;
+
+ inst->submode = target_submode;
+
+ if (phy->power_count) {
+ eq5_phy_init(phy);
+ return eq5_phy_power_on(phy);
+ }
+
+ return 0;
+}
+
+static const struct phy_ops eq5_phy_ops = {
+ .init = eq5_phy_init,
+ .exit = eq5_phy_exit,
+ .power_on = eq5_phy_power_on,
+ .power_off = eq5_phy_power_off,
+ .set_mode = eq5_phy_set_mode,
+ .validate = eq5_phy_validate,
+};
+
+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 device *dev, struct eq5_phy_private *priv,
+ unsigned int index, void __iomem *base,
+ unsigned int gp, unsigned int sgmii,
+ bool sgmii_support)
+{
+ struct eq5_phy_inst *inst = &priv->phys[index];
+ 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->dev = dev;
+ inst->phy = phy;
+ inst->gp = base + gp;
+ inst->sgmii = base + sgmii;
+ inst->sgmii_support = sgmii_support;
+ phy_set_drvdata(phy, inst);
+
+ /*
+ * Init inst->submode based on probe hardware state, allowing
+ * consumers to power us on without first setting the mode.
+ */
+ if (sgmii_support && (readl(inst->gp) & EQ5_GP_SGMII_MODE))
+ inst->submode = EQ5_PHY_SUBMODE_SGMII;
+ else
+ inst->submode = EQ5_PHY_SUBMODE_RGMII;
+
+ 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;
+
+ dev_set_drvdata(dev, priv);
+
+ base = (void __iomem *)dev_get_platdata(dev);
+
+ ret = eq5_phy_probe_phy(dev, priv, 0, base, EQ5_PHY0_GP,
+ EQ5_PHY0_SGMII, true);
+ if (ret)
+ return ret;
+
+ ret = eq5_phy_probe_phy(dev, priv, 1, base, EQ5_PHY1_GP,
+ EQ5_PHY1_SGMII, false);
+ if (ret)
+ return ret;
+
+ provider = devm_of_phy_provider_register(dev, eq5_phy_xlate);
+ if (IS_ERR(provider))
+ return dev_err_probe(dev, PTR_ERR(provider),
+ "registering provider failed\n");
+
+ return 0;
+}
+
+static const struct auxiliary_device_id eq5_phy_id_table[] = {
+ { .name = "clk_eyeq.phy" },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, eq5_phy_id_table);
+
+static struct auxiliary_driver eq5_phy_driver = {
+ .probe = eq5_phy_probe,
+ .id_table = eq5_phy_id_table,
+};
+module_auxiliary_driver(eq5_phy_driver);
+
+MODULE_DESCRIPTION("EyeQ5 Ethernet PHY driver");
+MODULE_AUTHOR("Théo Lebrun <theo.lebrun@bootlin.com>");
+MODULE_LICENSE("GPL");
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v9] phy: Add generic PHY driver used by MACB/GEM on EyeQ5
From: Théo Lebrun @ 2026-03-09 14:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: linux-phy, linux-kernel, linux-mips, Vladimir Kondratiev,
Gregory CLEMENT, Benoît Monin, Tawfik Bayouk,
Thomas Petazzoni, Luca Ceresoli, Théo Lebrun
EyeQ5 SoCs integrate two GEM instances. A system-controller register
region named "OLB" has some control over the Ethernet PHY integration.
Extend the current OLB ecosystem with a new generic PHY driver.
- OLB is carried by one main platform driver: clk-eyeq.
- It instantiates auxiliary devices: reset-eyeq & pinctrl-eyeq5.
- We add a new one: phy-eyeq5-eth.
About related patches:
- The MACB series [1] has been merged in v6.19-rc1. It makes MACB
consume a generic PHY from devicetree with the EyeQ5 compatible.
- clk patches are on the lkml [3]; they make clk-eyeq instantiate this
new auxiliary device. They also ensure we get a dev->of_node
assigned. Patches used to be [2] in the same series.
- MIPS patches are on the lkml [4]; they add MACB/GEM instances in
devicetree and their associated PHYs. They also update dt-bindings
to reflect this new feature OLB provides. Patches used to be [2] in
the same series.
Have a nice day,
Thanks!
Théo
[0]: https://lore.kernel.org/lkml/20250627-macb-v2-15-ff8207d0bb77@bootlin.com/
[1]: https://lore.kernel.org/lkml/20251022-macb-eyeq5-v2-0-7c140abb0581@bootlin.com/
[2]: https://lore.kernel.org/all/20260127-macb-phy-v6-0-cdd840588188@bootlin.com/
[3]: https://lore.kernel.org/all/20260225-macb-phy-v7-0-665bd8619d51@bootlin.com/
[4]: https://lore.kernel.org/all/20260225-macb-phy-v7-0-d3c9842ec931@bootlin.com/
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
Changes in v9:
- Explicitly cast dev_get_platdata() from `void *` to `void __iomem *`,
to fix "different address spaces" sparse warning.
- Link to v8: https://patch.msgid.link/20260306-macb-phy-v8-0-b5c48ee61402@bootlin.com
Changes in v8:
- Rebase upon linux-phy/next. Drop sorting Kconfig/Makefile patch
because one exists upstream.
- Instead of storing a phy_interface_t to know which submode to target,
store a custom enum with two states (RGMII/SGMII). Ignore RGMII
timings in this generic PHY driver because they are handled by the
net PHY.
- eq5_phy_set_mode() calls into eq5_phy_validate() and now propagates
its error return value. Previously it shadowed EINVAL with EOPNOTSUPP.
- Link to v7: https://lore.kernel.org/r/20260225-macb-phy-v7-0-e5211a61db56@bootlin.com
Changes in v7:
- Separate PHY / clk / MIPS patches into three series.
- Implement phy_validate().
- phy_power_on() now supports being called without a prior
phy_set_mode() because at probe we read the hardware state to
initialise inst->phy_instance.
- phy_set_mode() now support being called while the PHY is powered on.
- Add sgmii_support bool for each PHY instance to reject SGMII
configuration on PHY 1 which only supports RGMII.
- Drop dev_dbg() calls.
- Drop readl(gp) in phy_init().
- Replace inst->priv field by inst->dev; that is the only value we need
from the driver private data. Drop priv->dev field that is unused.
- Call into phy_exit() from phy_init() as the sequence is the same.
Add comment to explain the reasoning.
- Take Reviewed-by: Luca on "phy: sort Kconfig and Makefile".
- Rebase onto v7.0-rc1 and test on EyeQ5. Only diff to report:
PHY_COMMON_PROPS and PHY_COMMON_PROPS_TEST are kept at the top in the
sorting patch; we do not strictly respect an alphabetical ordering.
- Link to v6: https://lore.kernel.org/r/20260127-macb-phy-v6-0-cdd840588188@bootlin.com
Changes in v6:
- Rebase upon v6.19-rc7; nothing to report.
- Add new patch "phy: sort Kconfig and Makefile".
- phy-eyeq5-eth: drop useless explicit __iomem cast to
dev_get_platdata() return value.
- I did *not* drop the Kconfig `default MACH_EYEQ5` nor driver
`dev_dbg()`. I think both are useful and should be kept. See
last revision discussion here:
https://lore.kernel.org/lkml/DFGSMN8268O0.33TYCQDBVHUHZ@bootlin.com/
- Link to v5: https://lore.kernel.org/r/20251215-macb-phy-v5-0-a9dfea39da34@bootlin.com
Changes in v5:
- phy-eyeq5-eth:
- fix #includes: add delay, gfp_types, module and drop array_size,
bug, cleanup, container_of, lockdep, mutex.
- eq5_phy_xlate(): avoid magic value, use EQ5_PHY_COUNT.
- use dev_err_probe() in error cases of devm_phy_create() and
devm_of_phy_provider_register().
- 3x Reviewed-by: Luca Ceresoli.
- Add Neil Armstrong to Cc as new PHY subsystem reviewer.
- Rebase on v6.19-rc1, tested on hardware, no changes.
- Link to v4: https://lore.kernel.org/r/20251124-macb-phy-v4-0-955c625a81a7@bootlin.com
Changes in v4:
- Append my SoB to Jerome's patch:
[PATCH v4 3/7] clk: eyeq: use the auxiliary device creation helper
- Rebase on net-next & linux-{clk,mips,phy}. Nothing to report.
- Link to v3: https://lore.kernel.org/r/20251119-macb-phy-v3-0-e9a7be186a33@bootlin.com
Changes in v3:
- Take Philipp Zabel's Reviewed-by & Acked-by trailers on reset patch.
- Take Thomas Bogendoerfer's two Acked-by trailers on DT patches.
- Rebase on net-next & test on target. Nothing to report.
- Link to v2: https://lore.kernel.org/r/20251101-macb-phy-v2-0-c1519eef16d3@bootlin.com
Changes in v2:
- Take Acked-by: Conor Dooley on dt-bindings-patch.
- s/%ld/%tu/ for printing ptrdiff_t; warnings on 32-bit archs.
Reported by NIPA's netdev/build_32bit test.
https://patchwork.kernel.org/project/netdevbpf/patch/20251021-macb-eyeq5-v1-7-3b0b5a9d2f85@bootlin.com/
https://netdev.bots.linux.dev/static/nipa/1014126/14277857/build_32bit/stderr
- Link to v1: https://lore.kernel.org/r/20251022-macb-phy-v1-0-f29f28fae721@bootlin.com
Changes since MACB V1:
- Drop the old "mobileye,olb" properties from DT patches; found while
running dtbs_check and dt_binding_check.
- Drop all patches targeting net-next. That is MACB dt-bindings patch
and MACB driver code. See there here [1].
- Link to v1: https://lore.kernel.org/lkml/20251021-macb-eyeq5-v1-0-3b0b5a9d2f85@bootlin.com/
Past versions of MACB patches:
- March 2025: [PATCH net-next 00/13] Support the Cadence MACB/GEM
instances on Mobileye EyeQ5 SoCs
https://lore.kernel.org/lkml/20250321-macb-v1-0-537b7e37971d@bootlin.com/
- June 2025: [PATCH net-next v2 00/18] Support the Cadence MACB/GEM
instances on Mobileye EyeQ5 SoCs
https://lore.kernel.org/lkml/20250627-macb-v2-0-ff8207d0bb77@bootlin.com/
- August 2025: [PATCH net v3 00/16] net: macb: various fixes & cleanup
https://lore.kernel.org/lkml/20250808-macb-fixes-v3-0-08f1fcb5179f@bootlin.com/
---
Théo Lebrun (1):
phy: Add driver for EyeQ5 Ethernet PHY wrapper
MAINTAINERS | 1 +
drivers/phy/Kconfig | 13 ++
drivers/phy/Makefile | 1 +
drivers/phy/phy-eyeq5-eth.c | 280 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 295 insertions(+)
---
base-commit: caf08514bbee0736c31d8d4f406e3415cdf726bb
change-id: 20251022-macb-phy-21bc4e1dfbb7
Best regards,
--
Théo Lebrun <theo.lebrun@bootlin.com>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v2 8/8] mips: dts: Add PCIe to EcoNet EN751221
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
Add PCIe based on EN7528 PCIe driver, also add two MT76 wifi devices
to SmartFiber XP8421-B.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
arch/mips/boot/dts/econet/en751221.dtsi | 114 ++++++++++++++++++
.../econet/en751221_smartfiber_xp8421-b.dts | 21 ++++
arch/mips/econet/Kconfig | 2 +
3 files changed, 137 insertions(+)
diff --git a/arch/mips/boot/dts/econet/en751221.dtsi b/arch/mips/boot/dts/econet/en751221.dtsi
index 2abeef5b744a..72cb65654c34 100644
--- a/arch/mips/boot/dts/econet/en751221.dtsi
+++ b/arch/mips/boot/dts/econet/en751221.dtsi
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/dts-v1/;
+#include <dt-bindings/clock/econet,en751221-scu.h>
+
/ {
compatible = "econet,en751221";
#address-cells = <1>;
@@ -30,6 +32,30 @@ cpuintc: interrupt-controller {
#interrupt-cells = <1>;
};
+ chip_scu: syscon@1fa20000 {
+ compatible = "econet,en751221-chip-scu", "syscon";
+ reg = <0x1fa20000 0x388>;
+ };
+
+ pcie_phy1: pcie-phy@1fac0000 {
+ compatible = "econet,en751221-pcie-gen2";
+ reg = <0x1fac0000 0x1000>;
+ #phy-cells = <0>;
+ };
+
+ pcie_phy0: pcie-phy@1faf2000 {
+ compatible = "econet,en751221-pcie-gen1";
+ reg = <0x1faf2000 0x1000>;
+ #phy-cells = <0>;
+ };
+
+ scuclk: clock-controller@1fb00000 {
+ compatible = "econet,en751221-scu";
+ reg = <0x1fb00000 0x970>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
intc: interrupt-controller@1fb40000 {
compatible = "econet,en751221-intc";
reg = <0x1fb40000 0x100>;
@@ -41,6 +67,94 @@ intc: interrupt-controller@1fb40000 {
econet,shadow-interrupts = <7 2>, <8 3>, <13 12>, <30 29>;
};
+ pciecfg: pciecfg@1fb80000 {
+ compatible = "mediatek,generic-pciecfg", "syscon";
+ reg = <0x1fb80000 0x1000>;
+ };
+
+ pcie0: pcie@1fb81000 {
+ compatible = "econet,en7528-pcie";
+ device_type = "pci";
+ reg = <0x1fb81000 0x1000>;
+ reg-names = "port0";
+ linux,pci-domain = <0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <23>;
+ interrupt-names = "pcie_irq";
+ clocks = <&scuclk EN751221_CLK_PCIE>;
+ clock-names = "sys_ck0";
+ phys = <&pcie_phy0>;
+ phy-names = "pcie-phy0";
+ bus-range = <0x00 0xff>;
+ ranges = <0x01000000 0 0x00000000 0x1f600000 0 0x00008000>,
+ <0x82000000 0 0x20000000 0x20000000 0 0x08000000>;
+ status = "disabled";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+ <0 0 0 2 &pcie_intc0 1>,
+ <0 0 0 3 &pcie_intc0 2>,
+ <0 0 0 4 &pcie_intc0 3>;
+
+ pcie_intc0: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+
+ slot0: pcie@0,0 {
+ reg = <0x0000 0 0 0 0>;
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+ };
+
+ pcie1: pcie@1fb83000 {
+ compatible = "econet,en7528-pcie";
+ device_type = "pci";
+ reg = <0x1fb83000 0x1000>;
+ reg-names = "port1";
+ linux,pci-domain = <1>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <24>;
+ interrupt-names = "pcie_irq";
+ clocks = <&scuclk EN751221_CLK_PCIE>;
+ clock-names = "sys_ck1";
+ phys = <&pcie_phy1>;
+ phy-names = "pcie-phy1";
+ bus-range = <0x00 0xff>;
+ ranges = <0x81000000 0 0x00000000 0x1f608000 0 0x00008000>,
+ <0x82000000 0 0x28000000 0x28000000 0 0x08000000>;
+ status = "disabled";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+ <0 0 0 2 &pcie_intc1 1>,
+ <0 0 0 3 &pcie_intc1 2>,
+ <0 0 0 4 &pcie_intc1 3>;
+
+ pcie_intc1: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+
+ slot1: pcie@1,0 {
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+ };
+
uart: serial@1fbf0000 {
compatible = "ns16550";
reg = <0x1fbf0000 0x30>;
diff --git a/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts
index 8223c5bce67f..c633bf73add6 100644
--- a/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts
+++ b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts
@@ -17,3 +17,24 @@ chosen {
linux,usable-memory-range = <0x00020000 0x1bfe0000>;
};
};
+
+&pcie0 {
+ status = "okay";
+};
+&slot0 {
+ wifi@0,0 {
+ /* MT7612E */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ };
+};
+&pcie1 {
+ status = "okay";
+};
+&slot1 {
+ wifi@0,0 {
+ /* MT7592 */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ };
+};
diff --git a/arch/mips/econet/Kconfig b/arch/mips/econet/Kconfig
index fd69884cc9a8..b37b9d25d5a4 100644
--- a/arch/mips/econet/Kconfig
+++ b/arch/mips/econet/Kconfig
@@ -13,7 +13,9 @@ choice
bool "EN751221 family"
select COMMON_CLK
select ECONET_EN751221_INTC
+ select HAVE_PCI
select IRQ_MIPS_CPU
+ select PCI_DRIVERS_GENERIC
select SMP
select SMP_UP
select SYS_SUPPORTS_SMP
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 7/8] PCI: Skip bridge window reads when window is not supported
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel, Bjorn Helgaas
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
pci_read_bridge_io() and pci_read_bridge_mmio_pref() read bridge window
registers unconditionally. If the registers are hardwired to zero
(not implemented), both base and limit will be 0. Since (0 <= 0) is
true, a bogus window [mem 0x00000000-0x000fffff] or [io 0x0000-0x0fff]
gets created.
pci_read_bridge_windows() already detects unsupported windows by
testing register writability and sets io_window/pref_window flags
accordingly. Check these flags at the start of pci_read_bridge_io()
and pci_read_bridge_mmio_pref() to skip reading registers when the
window is not supported.
Suggested-by: Bjorn Helgaas <helgaas@kernel.org>
Link: https://lore.kernel.org/all/20260113210259.GA715789@bhelgaas/
Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
drivers/pci/probe.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bccc7a4bdd79..4eacb741b4ec 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -395,6 +395,9 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res,
unsigned long io_mask, io_granularity, base, limit;
struct pci_bus_region region;
+ if (!dev->io_window)
+ return;
+
io_mask = PCI_IO_RANGE_MASK;
io_granularity = 0x1000;
if (dev->io_window_1k) {
@@ -465,6 +468,9 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res,
pci_bus_addr_t base, limit;
struct pci_bus_region region;
+ if (!dev->pref_window)
+ return;
+
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 6/8] PCI: mediatek: Add support for EcoNet EN7528 SoC
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
Add support for the PCIe present on the EcoNet EN7528 (and EN751221) SoCs.
These SoCs have a mix of Gen1 and Gen2 capable ports, but the Gen2 ports
require re-training after startup.
Co-developed-by: Ahmed Naseef <naseefkm@gmail.com>
Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
drivers/pci/controller/Kconfig | 2 +-
drivers/pci/controller/pcie-mediatek.c | 118 +++++++++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 5aaed8ac6e44..f6a5fcacb38d 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -209,7 +209,7 @@ config PCI_MVEBU
config PCIE_MEDIATEK
tristate "MediaTek PCIe controller"
- depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
+ depends on ARCH_AIROHA || ARCH_MEDIATEK || ECONET || COMPILE_TEST
depends on OF
depends on PCI_MSI
select IRQ_MSI_LIB
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 5defa5cc4c2b..84064061652a 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -14,6 +14,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/irq-msi-lib.h>
#include <linux/irqdomain.h>
+#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/msi.h>
@@ -77,6 +78,7 @@
#define PCIE_CONF_VEND_ID 0x100
#define PCIE_CONF_DEVICE_ID 0x102
+#define PCIE_CONF_REV_CLASS 0x104
#define PCIE_CONF_CLASS_ID 0x106
#define PCIE_INT_MASK 0x420
@@ -89,6 +91,11 @@
#define MSI_MASK BIT(23)
#define MTK_MSI_IRQS_NUM 32
+#define EN7528_HOST_MODE 0x00804201
+#define EN7528_LINKUP_REG 0x50
+#define EN7528_RC0_LINKUP BIT(1)
+#define EN7528_RC1_LINKUP BIT(2)
+
#define PCIE_AHB_TRANS_BASE0_L 0x438
#define PCIE_AHB_TRANS_BASE0_H 0x43c
#define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0))
@@ -753,6 +760,86 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
return 0;
}
+static int mtk_pcie_startup_port_en7528(struct mtk_pcie_port *port)
+{
+ struct mtk_pcie *pcie = port->pcie;
+ struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+ struct resource *mem = NULL;
+ struct resource_entry *entry;
+ u32 val, link_mask;
+ int err;
+
+ entry = resource_list_first_type(&host->windows, IORESOURCE_MEM);
+ if (entry)
+ mem = entry->res;
+ if (!mem)
+ return -EINVAL;
+
+ if (!pcie->cfg) {
+ dev_err(pcie->dev, "EN7528: pciecfg syscon not available\n");
+ return -EINVAL;
+ }
+
+ /* Assert all reset signals */
+ writel(0, port->base + PCIE_RST_CTRL);
+
+ /*
+ * Enable PCIe link down reset, if link status changed from link up to
+ * link down, this will reset MAC control registers and configuration
+ * space.
+ */
+ writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+ /*
+ * Described in PCIe CEM specification sections 2.2 (PERST# Signal) and
+ * 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST#
+ * should be delayed 100ms (TPVPERL) for the power and clock to become
+ * stable.
+ */
+ msleep(100);
+
+ /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+ val = readl(port->base + PCIE_RST_CTRL);
+ val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+ PCIE_MAC_SRSTB | PCIE_CRSTB;
+ writel(val, port->base + PCIE_RST_CTRL);
+
+ writel(PCIE_CLASS_CODE | PCIE_REVISION_ID,
+ port->base + PCIE_CONF_REV_CLASS);
+ writel(EN7528_HOST_MODE, port->base);
+
+ link_mask = (port->slot == 0) ? EN7528_RC0_LINKUP : EN7528_RC1_LINKUP;
+
+ /* 100ms timeout value should be enough for Gen1/2 training */
+ err = regmap_read_poll_timeout(pcie->cfg, EN7528_LINKUP_REG, val,
+ !!(val & link_mask), 20,
+ 100 * USEC_PER_MSEC);
+ if (err) {
+ dev_err(pcie->dev, "EN7528: port%d link timeout\n", port->slot);
+ return -ETIMEDOUT;
+ }
+
+ /* Set INTx mask */
+ val = readl(port->base + PCIE_INT_MASK);
+ val &= ~INTX_MASK;
+ writel(val, port->base + PCIE_INT_MASK);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ mtk_pcie_enable_msi(port);
+
+ /* Set AHB to PCIe translation windows */
+ val = lower_32_bits(mem->start) |
+ AHB2PCIE_SIZE(fls(resource_size(mem)));
+ writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
+
+ val = upper_32_bits(mem->start);
+ writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
+
+ writel(WIN_ENABLE, port->base + PCIE_AXI_WINDOW0);
+
+ return 0;
+}
+
static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus,
unsigned int devfn, int where)
{
@@ -1149,6 +1236,30 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
+ /* Retrain Gen1 links to reach Gen2 where supported */
+ if (pcie->soc->startup == mtk_pcie_startup_port_en7528) {
+ struct pci_bus *bus = host->bus;
+ struct pci_dev *rc = NULL;
+
+ while ((rc = pci_get_class(PCI_CLASS_BRIDGE_PCI << 8, rc))) {
+ int ret = -EOPNOTSUPP;
+
+ if (rc->bus != bus)
+ continue;
+
+ #if IS_BUILTIN(CONFIG_PCIE_MEDIATEK)
+ ret = pcie_retrain_link(rc, true);
+ #endif
+
+ if (!ret)
+ dev_info(dev, "port%d link retrained\n",
+ PCI_SLOT(rc->devfn));
+ else
+ dev_info(dev, "port%d failed to retrain %pe\n",
+ PCI_SLOT(rc->devfn), ERR_PTR(ret));
+ }
+ }
+
return 0;
put_resources:
@@ -1264,8 +1375,15 @@ static const struct mtk_pcie_soc mtk_pcie_soc_mt7629 = {
.quirks = MTK_PCIE_FIX_CLASS_ID | MTK_PCIE_FIX_DEVICE_ID,
};
+static const struct mtk_pcie_soc mtk_pcie_soc_en7528 = {
+ .ops = &mtk_pcie_ops_v2,
+ .startup = mtk_pcie_startup_port_en7528,
+ .setup_irq = mtk_pcie_setup_irq,
+};
+
static const struct of_device_id mtk_pcie_ids[] = {
{ .compatible = "airoha,an7583-pcie", .data = &mtk_pcie_soc_an7583 },
+ { .compatible = "econet,en7528-pcie", .data = &mtk_pcie_soc_en7528 },
{ .compatible = "mediatek,mt2701-pcie", .data = &mtk_pcie_soc_v1 },
{ .compatible = "mediatek,mt7623-pcie", .data = &mtk_pcie_soc_v1 },
{ .compatible = "mediatek,mt2712-pcie", .data = &mtk_pcie_soc_mt2712 },
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 5/8] dt-bindings: PCI: mediatek: Add support for EcoNet EN7528
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
Introduce EcoNet EN7528 SoC compatible in MediaTek PCIe controller
binding.
EcoNet PCIe controller has the same configuration model as
Mediatek v2 but is initiallized more similarly to an MT7621
PCIe.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
Documentation/devicetree/bindings/pci/mediatek-pcie.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie.yaml b/Documentation/devicetree/bindings/pci/mediatek-pcie.yaml
index 0b8c78ec4f91..57cbfbff7a31 100644
--- a/Documentation/devicetree/bindings/pci/mediatek-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.yaml
@@ -14,6 +14,7 @@ properties:
oneOf:
- enum:
- airoha,an7583-pcie
+ - econet,en7528-pcie
- mediatek,mt2712-pcie
- mediatek,mt7622-pcie
- mediatek,mt7629-pcie
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 4/8] phy: econet: Add PCIe PHY driver for EcoNet EN751221 and EN7528 SoCs.
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
Introduce support for EcoNet PCIe PHY controllers found in EN751221
and EN7528 SoCs, these SoCs are not identical but are similar, each
having one Gen1 port, and one Gen1/Gen2 port.
Co-developed-by: Ahmed Naseef <naseefkm@gmail.com>
Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
[cjd@cjdns.fr: add EN751221 support and refactor for clarity]
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
MAINTAINERS | 1 +
drivers/phy/Kconfig | 12 +++
drivers/phy/Makefile | 1 +
drivers/phy/phy-econet-pcie.c | 180 ++++++++++++++++++++++++++++++++++
4 files changed, 194 insertions(+)
create mode 100644 drivers/phy/phy-econet-pcie.c
diff --git a/MAINTAINERS b/MAINTAINERS
index bc925fa08baa..e61a349864fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9127,6 +9127,7 @@ M: Caleb James DeLisle <cjd@cjdns.fr>
L: linux-mips@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml
+F: drivers/phy/phy-econet-pcie.c
ECRYPT FILE SYSTEM
M: Tyler Hicks <code@tyhicks.com>
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 02467dfd4fb0..60efc37f6eb0 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -123,6 +123,18 @@ config PHY_AIROHA_PCIE
This driver create the basic PHY instance and provides initialize
callback for PCIe GEN3 port.
+config PHY_ECONET_PCIE
+ tristate "EcoNet PCIe-PHY Driver"
+ depends on ECONET || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ select REGMAP_MMIO
+ help
+ Say Y here to add support for EcoNet PCIe PHY driver.
+ This driver create the basic PHY instance and provides initialize
+ callback for PCIe GEN1 and GEN2 ports. This PHY is found on
+ EcoNet SoCs including EN751221 and EN7528.
+
config PHY_NXP_PTN3222
tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver"
depends on I2C
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index a648c2e02a83..a77f182ee8f3 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
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_ECONET_PCIE) += phy-econet-pcie.o
obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-spacemit-k1-pcie.o
obj-$(CONFIG_GENERIC_PHY) += allwinner/ \
diff --git a/drivers/phy/phy-econet-pcie.c b/drivers/phy/phy-econet-pcie.c
new file mode 100644
index 000000000000..d2c6e0c1f331
--- /dev/null
+++ b/drivers/phy/phy-econet-pcie.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Author: Caleb James DeLisle <cjd@cjdns.fr>
+ * Ahmed Naseef <naseefkm@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* Rx detection timing for EN751221: 16*8 clock cycles */
+#define EN751221_RXDET_VAL 16
+
+/* Rx detection timing when in power mode 3 */
+#define EN75_RXDET_P3_REG 0xa28
+#define EN75_RXDET_P3_MASK GENMASK(17, 9)
+
+/* Rx detection timing when in power mode 2 */
+#define EN75_RXDET_P2_REG 0xa2c
+#define EN75_RXDET_P2_MASK GENMASK(8, 0)
+
+/* Rx impedance */
+#define EN75_RX_IMPEDANCE_REG 0xb2c
+#define EN75_RX_IMPEDANCE_MASK GENMASK(13, 12)
+enum en75_rx_impedance {
+ EN75_RX_IMPEDANCE_100_OHM = 0,
+ EN75_RX_IMPEDANCE_95_OHM = 1,
+ EN75_RX_IMPEDANCE_90_OHM = 2,
+};
+
+/* PLL Invert clock */
+#define EN75_PLL_PH_INV_REG 0x4a0
+#define EN75_PLL_PH_INV_MASK BIT(5)
+
+struct en75_phy_op {
+ u32 reg;
+ u32 mask;
+ u32 val;
+};
+
+struct en7528_pcie_phy {
+ struct regmap *regmap;
+ const struct en75_phy_op *data;
+};
+
+/* Port 0 PHY: set LCDDS_CLK_PH_INV for PLL operation */
+static const struct en75_phy_op en7528_phy_gen1[] = {
+ {
+ .reg = EN75_PLL_PH_INV_REG,
+ .mask = EN75_PLL_PH_INV_MASK,
+ .val = 1,
+ },
+ { /* sentinel */ }
+};
+
+/* EN7528 Port 1 PHY: Rx impedance tuning, target R -5 Ohm */
+static const struct en75_phy_op en7528_phy_gen2[] = {
+ {
+ .reg = EN75_RX_IMPEDANCE_REG,
+ .mask = EN75_RX_IMPEDANCE_MASK,
+ .val = EN75_RX_IMPEDANCE_95_OHM,
+ },
+ { /* sentinel */ }
+};
+
+/* EN751221 Port 1 PHY, set RX detect to 16*8 clock cycles */
+static const struct en75_phy_op en751221_phy_gen2[] = {
+ {
+ .reg = EN75_RXDET_P3_REG,
+ .mask = EN75_RXDET_P3_MASK,
+ .val = EN751221_RXDET_VAL,
+ },
+ {
+ .reg = EN75_RXDET_P2_REG,
+ .mask = EN75_RXDET_P2_MASK,
+ .val = EN751221_RXDET_VAL,
+ },
+ { /* sentinel */ }
+};
+
+static int en75_pcie_phy_init(struct phy *phy)
+{
+ struct en7528_pcie_phy *ephy = phy_get_drvdata(phy);
+ const struct en75_phy_op *data = ephy->data;
+ int i, ret;
+ u32 val;
+
+ for (i = 0; data[i].mask || data[i].val; i++) {
+ if (i)
+ usleep_range(1000, 2000);
+
+ val = field_prep(data[i].mask, data[i].val);
+
+ ret = regmap_update_bits(ephy->regmap, data[i].reg,
+ data[i].mask, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops en75_pcie_phy_ops = {
+ .init = en75_pcie_phy_init,
+ .owner = THIS_MODULE,
+};
+
+static int en75_pcie_phy_probe(struct platform_device *pdev)
+{
+ struct regmap_config regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ };
+ struct device *dev = &pdev->dev;
+ const struct en75_phy_op *data;
+ struct phy_provider *provider;
+ struct en7528_pcie_phy *ephy;
+ void __iomem *base;
+ struct phy *phy;
+ int i;
+
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL);
+ if (!ephy)
+ return -ENOMEM;
+
+ ephy->data = data;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ /* Set max_register to highest used register */
+ for (i = 0; data[i].mask || data[i].val; i++)
+ if (data[i].reg > regmap_config.max_register)
+ regmap_config.max_register = data[i].reg;
+
+ ephy->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
+ if (IS_ERR(ephy->regmap))
+ return PTR_ERR(ephy->regmap);
+
+ phy = devm_phy_create(dev, dev->of_node, &en75_pcie_phy_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ phy_set_drvdata(phy, ephy);
+
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id en75_pcie_phy_ids[] = {
+ { .compatible = "econet,en7528-pcie-gen1", .data = en7528_phy_gen1 },
+ { .compatible = "econet,en7528-pcie-gen2", .data = en7528_phy_gen2 },
+ { .compatible = "econet,en751221-pcie-gen1", .data = en7528_phy_gen1 },
+ { .compatible = "econet,en751221-pcie-gen2", .data = en751221_phy_gen2 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, en75_pcie_phy_ids);
+
+static struct platform_driver en75_pcie_phy_driver = {
+ .probe = en75_pcie_phy_probe,
+ .driver = {
+ .name = "econet-pcie-phy",
+ .of_match_table = en75_pcie_phy_ids,
+ },
+};
+module_platform_driver(en75_pcie_phy_driver);
+
+MODULE_AUTHOR("Caleb James DeLisle <cjd@cjdns.fr>");
+MODULE_DESCRIPTION("EcoNet PCIe PHY driver");
+MODULE_LICENSE("GPL");
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 3/8] dt-bindings: phy: Document PCIe PHY in EcoNet EN751221 and EN7528
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
EN751221 and EN7528 SoCs have two PCIe slots, and each one has a PHY
which behaves slightly differently because one slot is Gen1/Gen2 while
the other is Gen1 only.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
.../phy/econet,en751221-pcie-phy.yaml | 50 +++++++++++++++++++
MAINTAINERS | 6 +++
2 files changed, 56 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml
new file mode 100644
index 000000000000..987d396c1c64
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/econet,en751221-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: EcoNet PCI-Express PHY for EcoNet EN751221 and EN7528
+
+maintainers:
+ - Caleb James DeLisle <cjd@cjdns.fr>
+
+description:
+ The PCIe PHY supports physical layer functionality for PCIe Gen1 and
+ Gen1/Gen2 ports. On these SoCs, port 0 is a Gen1-only port while
+ port 1 is Gen1/Gen2 capable.
+
+properties:
+ compatible:
+ enum:
+ - econet,en751221-pcie-gen1
+ - econet,en751221-pcie-gen2
+ - econet,en7528-pcie-gen1
+ - econet,en7528-pcie-gen2
+
+ reg:
+ maxItems: 1
+
+ "#phy-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pcie-phy@1faf2000 {
+ compatible = "econet,en7528-pcie-gen1";
+ reg = <0x1faf2000 0x1000>;
+ #phy-cells = <0>;
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 3781d55db5bb..bc925fa08baa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9122,6 +9122,12 @@ F: drivers/irqchip/irq-econet-en751221.c
F: include/dt-bindings/clock/econet,en751221-scu.h
F: include/dt-bindings/reset/econet,en751221-scu.h
+ECONET PCIE PHY DRIVER
+M: Caleb James DeLisle <cjd@cjdns.fr>
+L: linux-mips@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml
+
ECRYPT FILE SYSTEM
M: Tyler Hicks <code@tyhicks.com>
L: ecryptfs@vger.kernel.org
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 2/8] clk: airoha: Add econet EN751221 clock/reset support to en7523-scu
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
EcoNet EN751221 clock/reset driver is significantly similar to the
EN7523 / EN7581, however the EN751221 does not have a neat batch of clock
divider registers so there are fewer known clocks, and the frequency of
each clock is derived differently. This clock driver will probably work
correctly on EN751627, EN7528, and EN7580.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
drivers/clk/Kconfig | 6 +-
drivers/clk/clk-en7523.c | 238 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 236 insertions(+), 8 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3d803b4cf5c1..47df6073a72b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -218,13 +218,13 @@ config COMMON_CLK_CS2000_CP
If you say yes here you get support for the CS2000 clock multiplier.
config COMMON_CLK_EN7523
- bool "Clock driver for Airoha EN7523 SoC system clocks"
+ bool "Clock driver for Airoha/EcoNet SoC system clocks"
depends on OF
- depends on ARCH_AIROHA || COMPILE_TEST
+ depends on ARCH_AIROHA || ECONET || COMPILE_TEST
default ARCH_AIROHA
help
This driver provides the fixed clocks and gates present on Airoha
- ARM silicon.
+ and EcoNet silicon.
config COMMON_CLK_EP93XX
tristate "Clock driver for Cirrus Logic ep93xx SoC"
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index 08cc8e5acf43..f7bd7034cf7f 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
@@ -11,6 +12,8 @@
#include <dt-bindings/clock/en7523-clk.h>
#include <dt-bindings/reset/airoha,en7523-reset.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
+#include <dt-bindings/clock/econet,en751221-scu.h>
+#include <dt-bindings/reset/econet,en751221-scu.h>
#define RST_NR_PER_BANK 32
@@ -33,15 +36,49 @@
#define REG_RESET_CONTROL_PCIEHB BIT(29)
#define REG_RESET_CONTROL_PCIE1 BIT(27)
#define REG_RESET_CONTROL_PCIE2 BIT(26)
+#define REG_HIR 0x064
+#define REG_HIR_MASK GENMASK(31, 16)
/* EN7581 */
#define REG_NP_SCU_PCIC 0x88
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
#define REG_CRYPTO_CLKSRC2 0x20c
+/* EN751221 */
+#define EN751221_REG_SPI_DIV 0x0cc
+#define EN751221_REG_SPI_DIV_MASK GENMASK(31, 8)
+#define EN751221_SPI_BASE 500000000
+#define EN751221_SPI_BASE_EN7526C 400000000
+#define EN751221_REG_BUS 0x284
+#define EN751221_REG_BUS_MASK GENMASK(21, 12)
+#define EN751221_REG_SSR3 0x094
+#define EN751221_REG_SSR3_GSW_MASK GENMASK(9, 8)
#define REG_RST_CTRL2 0x830
#define REG_RST_CTRL1 0x834
+#define EN751221_REG_RST_DMT 0x84
+#define EN751221_REG_RST_USB 0xec
+
+#define EN751221_MAX_CLKS 6
+
+enum en_hir {
+ HIR_UNKNOWN = -1,
+ HIR_TC3169 = 0,
+ HIR_TC3182 = 1,
+ HIR_RT65168 = 2,
+ HIR_RT63165 = 3,
+ HIR_RT63365 = 4,
+ HIR_MT751020 = 5,
+ HIR_MT7505 = 6,
+ HIR_EN751221 = 7,
+ HIR_EN7526C = 8,
+ HIR_EN751627 = 9,
+ HIR_EN7580 = 10,
+ HIR_EN7528 = 11,
+ HIR_EN7523 = 12,
+ HIR_EN7581 = 13,
+ HIR_MAX = 14,
+};
struct en_clk_desc {
int id;
@@ -93,6 +130,8 @@ static const u32 bus7581_base[] = { 600000000, 540000000 };
static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
static const u32 crypto_base[] = { 540000000, 480000000 };
static const u32 emmc7581_base[] = { 200000000, 150000000 };
+/* EN751221 */
+static const u32 gsw751221_base[] = { 500000000, 250000000, 400000000, 200000000 };
static const struct en_clk_desc en7523_base_clks[] = {
{
@@ -300,6 +339,13 @@ static const u16 en7581_rst_ofs[] = {
REG_RST_CTRL1,
};
+static const u16 en751221_rst_ofs[] = {
+ REG_RST_CTRL2,
+ REG_RST_CTRL1,
+ EN751221_REG_RST_DMT,
+ EN751221_REG_RST_USB,
+};
+
static const u16 en7523_rst_map[] = {
/* RST_CTRL2 */
[EN7523_XPON_PHY_RST] = 0,
@@ -405,8 +451,61 @@ static const u16 en7581_rst_map[] = {
[EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
};
+static const u16 en751221_rst_map[] = {
+ /* RST_CTRL2 */
+ [EN751221_XPON_PHY_RST] = 0,
+ [EN751221_GFAST_RST] = 1,
+ [EN751221_CPU_TIMER2_RST] = 2,
+ [EN751221_UART3_RST] = 3,
+ [EN751221_UART4_RST] = 4,
+ [EN751221_UART5_RST] = 5,
+ [EN751221_I2C2_RST] = 6,
+ [EN751221_XSI_MAC_RST] = 7,
+ [EN751221_XSI_PHY_RST] = 8,
+
+ /* RST_CTRL1 */
+ [EN751221_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [EN751221_FE_QDMA1_RST] = RST_NR_PER_BANK + 1,
+ [EN751221_FE_QDMA2_RST] = RST_NR_PER_BANK + 2,
+ [EN751221_FE_UNZIP_RST] = RST_NR_PER_BANK + 3,
+ [EN751221_PCM2_RST] = RST_NR_PER_BANK + 4,
+ [EN751221_PTM_MAC_RST] = RST_NR_PER_BANK + 5,
+ [EN751221_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [EN751221_SAR_RST] = RST_NR_PER_BANK + 7,
+ [EN751221_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [EN751221_INTC_RST] = RST_NR_PER_BANK + 9,
+ [EN751221_BONDING_RST] = RST_NR_PER_BANK + 10,
+ [EN751221_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [EN751221_UART_RST] = RST_NR_PER_BANK + 12,
+ [EN751221_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [EN751221_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [EN751221_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [EN751221_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [EN751221_SFC_RST] = RST_NR_PER_BANK + 18,
+ [EN751221_UART2_RST] = RST_NR_PER_BANK + 19,
+ [EN751221_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [EN751221_FE_RST] = RST_NR_PER_BANK + 21,
+ [EN751221_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [EN751221_GSW_RST] = RST_NR_PER_BANK + 23,
+ [EN751221_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [EN751221_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [EN751221_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [EN751221_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
+ [EN751221_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [EN751221_SIMIF_RST] = RST_NR_PER_BANK + 30,
+ [EN751221_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+
+ /* RST_DMT */
+ [EN751221_DMT_RST] = 2 * RST_NR_PER_BANK + 0,
+
+ /* RST_USB */
+ [EN751221_USB_PHY_P0_RST] = 3 * RST_NR_PER_BANK + 6,
+ [EN751221_USB_PHY_P1_RST] = 3 * RST_NR_PER_BANK + 7,
+};
+
static int en7581_reset_register(struct device *dev, void __iomem *base,
- const u16 *rst_map, int nr_resets);
+ const u16 *rst_map, int nr_resets,
+ const u16 *rst_reg_ofs);
static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val)
{
@@ -604,7 +703,8 @@ static int en7523_clk_hw_init(struct platform_device *pdev,
en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
return en7581_reset_register(&pdev->dev, np_base, en7523_rst_map,
- ARRAY_SIZE(en7523_rst_map));
+ ARRAY_SIZE(en7523_rst_map),
+ en7581_rst_ofs);
}
static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
@@ -705,7 +805,8 @@ static const struct reset_control_ops en7581_reset_ops = {
};
static int en7581_reset_register(struct device *dev, void __iomem *base,
- const u16 *rst_map, int nr_resets)
+ const u16 *rst_map, int nr_resets,
+ const u16 *rst_reg_ofs)
{
struct en_rst_data *rst_data;
@@ -713,7 +814,7 @@ static int en7581_reset_register(struct device *dev, void __iomem *base,
if (!rst_data)
return -ENOMEM;
- rst_data->bank_ofs = en7581_rst_ofs;
+ rst_data->bank_ofs = rst_reg_ofs;
rst_data->idx_map = rst_map;
rst_data->base = base;
@@ -752,7 +853,123 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
writel(val | 3, base + REG_NP_SCU_PCIC);
return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
- ARRAY_SIZE(en7581_rst_map));
+ ARRAY_SIZE(en7581_rst_map),
+ en7581_rst_ofs);
+}
+
+static enum en_hir get_hw_id(void __iomem *np_base)
+{
+ u32 val = FIELD_GET(REG_HIR_MASK, readl(np_base + REG_HIR));
+
+ if (val < HIR_MAX)
+ return (enum en_hir) val;
+
+ return HIR_UNKNOWN;
+}
+
+static void en751221_try_register_clk(struct device *dev, int key,
+ struct clk_hw_onecell_data *clk_data,
+ const char *name, u32 rate)
+{
+ struct clk_hw *hw;
+
+ hw = clk_hw_register_fixed_rate(dev, name, NULL, 0, rate);
+ if (IS_ERR(hw) || key >= EN751221_MAX_CLKS)
+ pr_err("Failed to register clk %s: %pe\n", name, hw);
+ else
+ clk_data->hws[key] = hw;
+}
+
+static void en751221_register_clocks(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ struct regmap *map, void __iomem *np_base)
+{
+ enum en_hir hid = get_hw_id(np_base);
+ struct clk_hw *hw;
+ u32 rate;
+ u32 div;
+ int err;
+
+ /* PCI */
+ hw = en7523_register_pcie_clk(dev, np_base);
+ clk_data->hws[EN751221_CLK_PCIE] = hw;
+
+ /* SPI */
+ rate = EN751221_SPI_BASE;
+ if (hid == HIR_EN7526C)
+ rate = EN751221_SPI_BASE_EN7526C;
+
+ err = regmap_read(map, EN751221_REG_SPI_DIV, &div);
+ if (err) {
+ pr_err("Failed reading fixed clk div %s: %d\n",
+ "spi", err);
+ } else {
+ div = FIELD_GET(EN751221_REG_SPI_DIV_MASK, div) * 2;
+ if (!div)
+ div = 40;
+
+ en751221_try_register_clk(dev, EN751221_CLK_SPI, clk_data,
+ "spi", rate / div);
+ }
+
+ /* BUS */
+ rate = FIELD_GET(EN751221_REG_BUS_MASK,
+ readl(np_base + EN751221_REG_BUS));
+ rate *= 1000000;
+ en751221_try_register_clk(dev, EN751221_CLK_BUS, clk_data, "bus",
+ rate);
+
+ /* CPU */
+ en751221_try_register_clk(dev, EN751221_CLK_CPU, clk_data, "cpu",
+ rate * 4);
+
+ /* HPT */
+ switch (hid) {
+ case HIR_EN751221:
+ case HIR_EN751627:
+ case HIR_EN7526C:
+ case HIR_EN7580:
+ case HIR_EN7528:
+ rate = 200000000;
+ break;
+ case HIR_MT7505:
+ rate = 100000000;
+ break;
+ case HIR_MT751020:
+ rate = 800000000 / 3;
+ break;
+ default:
+ rate = 250000000;
+ }
+ en751221_try_register_clk(dev, EN751221_CLK_HPT, clk_data, "hpt",
+ rate);
+
+ /* GSW */
+ rate = FIELD_GET(EN751221_REG_SSR3_GSW_MASK,
+ readl(np_base + EN751221_REG_SSR3));
+ en751221_try_register_clk(dev, EN751221_CLK_GSW, clk_data, "gsw",
+ gsw751221_base[rate]);
+}
+
+static int en751221_clk_hw_init(struct platform_device *pdev,
+ struct clk_hw_onecell_data *clk_data)
+{
+ struct regmap *map;
+ void __iomem *base;
+
+ map = syscon_regmap_lookup_by_compatible("econet,en751221-chip-scu");
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ en751221_register_clocks(&pdev->dev, clk_data, map, base);
+
+ return en7581_reset_register(&pdev->dev, base, en751221_rst_map,
+ ARRAY_SIZE(en751221_rst_map),
+ en751221_rst_ofs);
}
static int en7523_clk_probe(struct platform_device *pdev)
@@ -799,9 +1016,20 @@ static const struct en_clk_soc_data en7581_data = {
.hw_init = en7581_clk_hw_init,
};
+static const struct en_clk_soc_data en751221_data = {
+ .num_clocks = EN751221_MAX_CLKS,
+ .pcie_ops = {
+ .is_enabled = en7523_pci_is_enabled,
+ .prepare = en7523_pci_prepare,
+ .unprepare = en7523_pci_unprepare,
+ },
+ .hw_init = en751221_clk_hw_init,
+};
+
static const struct of_device_id of_match_clk_en7523[] = {
{ .compatible = "airoha,en7523-scu", .data = &en7523_data },
{ .compatible = "airoha,en7581-scu", .data = &en7581_data },
+ { .compatible = "econet,en751221-scu", .data = &en751221_data },
{ /* sentinel */ }
};
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 1/8] dt-bindings: clock, reset: Add econet EN751221
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
In-Reply-To: <20260309131818.74467-1-cjd@cjdns.fr>
Add clock and reset bindings for EN751221 as well as a "chip-scu" which is
an additional regmap that is used by the clock driver as well as others.
This split of the SCU across two register areas is the same as the Airoha
AN758x family.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
.../bindings/clock/airoha,en7523-scu.yaml | 7 ++-
.../devicetree/bindings/mfd/syscon.yaml | 2 +
MAINTAINERS | 2 +
.../dt-bindings/clock/econet,en751221-scu.h | 13 +++++
.../dt-bindings/reset/econet,en751221-scu.h | 49 +++++++++++++++++++
5 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 include/dt-bindings/clock/econet,en751221-scu.h
create mode 100644 include/dt-bindings/reset/econet,en751221-scu.h
diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
index a8471367175b..91abe7716fce 100644
--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
+++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
@@ -32,6 +32,7 @@ properties:
- enum:
- airoha,en7523-scu
- airoha,en7581-scu
+ - econet,en751221-scu
reg:
items:
@@ -67,7 +68,10 @@ allOf:
- if:
properties:
compatible:
- const: airoha,en7581-scu
+ items:
+ - enum:
+ - airoha,en7581-scu
+ - econet,en751221-scu
then:
properties:
reg:
@@ -98,3 +102,4 @@ examples:
#reset-cells = <1>;
};
};
+
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index e57add2bacd3..e22867088063 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -61,6 +61,7 @@ select:
- cirrus,ep7209-syscon2
- cirrus,ep7209-syscon3
- cnxt,cx92755-uc
+ - econet,en751221-chip-scu
- freecom,fsg-cs2-system-controller
- fsl,imx93-aonmix-ns-syscfg
- fsl,imx93-wakeupmix-syscfg
@@ -173,6 +174,7 @@ properties:
- cirrus,ep7209-syscon2
- cirrus,ep7209-syscon3
- cnxt,cx92755-uc
+ - econet,en751221-chip-scu
- freecom,fsg-cs2-system-controller
- fsl,imx93-aonmix-ns-syscfg
- fsl,imx93-wakeupmix-syscfg
diff --git a/MAINTAINERS b/MAINTAINERS
index 14899f1de77e..3781d55db5bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9119,6 +9119,8 @@ F: arch/mips/boot/dts/econet/
F: arch/mips/econet/
F: drivers/clocksource/timer-econet-en751221.c
F: drivers/irqchip/irq-econet-en751221.c
+F: include/dt-bindings/clock/econet,en751221-scu.h
+F: include/dt-bindings/reset/econet,en751221-scu.h
ECRYPT FILE SYSTEM
M: Tyler Hicks <code@tyhicks.com>
diff --git a/include/dt-bindings/clock/econet,en751221-scu.h b/include/dt-bindings/clock/econet,en751221-scu.h
new file mode 100644
index 000000000000..44a5b197cb06
--- /dev/null
+++ b/include/dt-bindings/clock/econet,en751221-scu.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_CLOCK_ECONET_EN751221_SCU_H_
+#define _DT_BINDINGS_CLOCK_ECONET_EN751221_SCU_H_
+
+#define EN751221_CLK_PCIE 0
+#define EN751221_CLK_SPI 1
+#define EN751221_CLK_BUS 2
+#define EN751221_CLK_CPU 3
+#define EN751221_CLK_HPT 4
+#define EN751221_CLK_GSW 5
+
+#endif /* _DT_BINDINGS_CLOCK_ECONET_EN751221_SCU_H_ */
diff --git a/include/dt-bindings/reset/econet,en751221-scu.h b/include/dt-bindings/reset/econet,en751221-scu.h
new file mode 100644
index 000000000000..bad499d4d50a
--- /dev/null
+++ b/include/dt-bindings/reset/econet,en751221-scu.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef __DT_BINDINGS_RESET_CONTROLLER_ECONET_EN751221_H_
+#define __DT_BINDINGS_RESET_CONTROLLER_ECONET_EN751221_H_
+
+#define EN751221_XPON_PHY_RST 0
+#define EN751221_PCM1_ZSI_ISI_RST 1
+#define EN751221_FE_QDMA1_RST 2
+#define EN751221_FE_QDMA2_RST 3
+#define EN751221_FE_UNZIP_RST 4
+#define EN751221_PCM2_RST 5
+#define EN751221_PTM_MAC_RST 6
+#define EN751221_CRYPTO_RST 7
+#define EN751221_SAR_RST 8
+#define EN751221_TIMER_RST 9
+#define EN751221_INTC_RST 10
+#define EN751221_BONDING_RST 11
+#define EN751221_PCM1_RST 12
+#define EN751221_UART_RST 13
+#define EN751221_GPIO_RST 14
+#define EN751221_GDMA_RST 15
+#define EN751221_I2C_MASTER_RST 16
+#define EN751221_PCM2_ZSI_ISI_RST 17
+#define EN751221_SFC_RST 18
+#define EN751221_UART2_RST 19
+#define EN751221_GDMP_RST 20
+#define EN751221_FE_RST 21
+#define EN751221_USB_HOST_P0_RST 22
+#define EN751221_GSW_RST 23
+#define EN751221_SFC2_PCM_RST 24
+#define EN751221_PCIE0_RST 25
+#define EN751221_PCIE1_RST 26
+#define EN751221_CPU_TIMER_RST 27
+#define EN751221_PCIE_HB_RST 28
+#define EN751221_SIMIF_RST 29
+#define EN751221_XPON_MAC_RST 30
+#define EN751221_GFAST_RST 31
+#define EN751221_CPU_TIMER2_RST 32
+#define EN751221_UART3_RST 33
+#define EN751221_UART4_RST 34
+#define EN751221_UART5_RST 35
+#define EN751221_I2C2_RST 36
+#define EN751221_XSI_MAC_RST 37
+#define EN751221_XSI_PHY_RST 38
+#define EN751221_DMT_RST 39
+#define EN751221_USB_PHY_P0_RST 40
+#define EN751221_USB_PHY_P1_RST 41
+
+#endif /* __DT_BINDINGS_RESET_CONTROLLER_ECONET_EN751221_H_ */
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 0/8] mips: econet: Add clk/reset and PCIe support
From: Caleb James DeLisle @ 2026-03-09 13:18 UTC (permalink / raw)
To: linux-mips
Cc: naseefkm, mturquette, sboyd, robh, krzk+dt, conor+dt, cjd,
tsbogend, ryder.lee, jianjun.wang, lpieralisi, kwilczynski, mani,
bhelgaas, vkoul, neil.armstrong, p.zabel, matthias.bgg,
angelogioacchino.delregno, nbd, ansuelsmth, linux-clk, devicetree,
linux-kernel, linux-pci, linux-mediatek, linux-phy,
linux-arm-kernel
Add clock/reset and PCIe support to EcoNet EN751221 and related SoCs.
This builds on the Airoha EN7523 clock driver and the Mediatek PCIe driver.
Patch 6 is upstreaming of Ahmed Naseef's work on EcoNet PCIe, which was
developed to support the EN7528, but which works equally on the EN751221.
There is also a workaround in patch 7 to gracefully handle PCI hardware
which does not advertize a bridge window and instead always reads zero.
Changes in v2:
* clock/econet,en751221-scu.h drop EN751221_MAX_CLKS
* clk-en7523.c add EN751221_MAX_CLKS
* econet,en751221-chip-scu.yaml drop in favor of using mtd/syscon.yaml
* airoha,en7523-scu.yaml drop redundant example
* econet,en751221-pcie-phy.yaml Refer to PHYs as "gen1" and "gen2"
* pcie-mediatek.c Exclude pcie_retrain_link() when building as a module
* en751221.dtsi "econet,en751221-scu" is not a "syscon"
* Rebase to linux-next
* v1: https://lore.kernel.org/linux-mips/20260303190948.694783-1-cjd@cjdns.fr/
Caleb James DeLisle (8):
dt-bindings: clock, reset: Add econet EN751221
clk: airoha: Add econet EN751221 clock/reset support to en7523-scu
dt-bindings: phy: Document PCIe PHY in EcoNet EN751221 and EN7528
phy: econet: Add PCIe PHY driver for EcoNet EN751221 and EN7528 SoCs.
dt-bindings: PCI: mediatek: Add support for EcoNet EN7528
PCI: mediatek: Add support for EcoNet EN7528 SoC
PCI: Skip bridge window reads when window is not supported
mips: dts: Add PCIe to EcoNet EN751221
.../bindings/clock/airoha,en7523-scu.yaml | 7 +-
.../devicetree/bindings/mfd/syscon.yaml | 2 +
.../bindings/pci/mediatek-pcie.yaml | 1 +
.../phy/econet,en751221-pcie-phy.yaml | 50 ++++
MAINTAINERS | 9 +
arch/mips/boot/dts/econet/en751221.dtsi | 114 +++++++++
.../econet/en751221_smartfiber_xp8421-b.dts | 21 ++
arch/mips/econet/Kconfig | 2 +
drivers/clk/Kconfig | 6 +-
drivers/clk/clk-en7523.c | 238 +++++++++++++++++-
drivers/pci/controller/Kconfig | 2 +-
drivers/pci/controller/pcie-mediatek.c | 118 +++++++++
drivers/pci/probe.c | 6 +
drivers/phy/Kconfig | 12 +
drivers/phy/Makefile | 1 +
drivers/phy/phy-econet-pcie.c | 180 +++++++++++++
.../dt-bindings/clock/econet,en751221-scu.h | 13 +
.../dt-bindings/reset/econet,en751221-scu.h | 49 ++++
18 files changed, 821 insertions(+), 10 deletions(-)
create mode 100644 Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml
create mode 100644 drivers/phy/phy-econet-pcie.c
create mode 100644 include/dt-bindings/clock/econet,en751221-scu.h
create mode 100644 include/dt-bindings/reset/econet,en751221-scu.h
base-commit: 3fa5e5702a82d259897bd7e209469bc06368bf31
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v9 03/23] dt-bindings: ufs: mediatek,ufs: Add mt8196 variant
From: Nicolas Frattaroli @ 2026-03-09 10:04 UTC (permalink / raw)
To: Martin K. Petersen
Cc: Rob Herring, Alim Akhtar, Avri Altman, Bart Van Assche,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Chunfeng Yun, Vinod Koul,
Kishon Vijay Abraham I, Peter Wang, Stanley Jhu,
James E.J. Bottomley, Martin K. Petersen, Philipp Zabel,
Liam Girdwood, Mark Brown, Chaotian Jing, Neil Armstrong,
Louis-Alexis Eyraud, kernel, linux-scsi, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, linux-phy, Conor Dooley
In-Reply-To: <yq14imrwp3z.fsf@ca-mkp.ca.oracle.com>
On Saturday, 7 March 2026 19:01:17 Central European Standard Time Martin K. Petersen wrote:
>
> Nicolas,
>
> >> "ufs" is redundant as all the clocks are for UFS. Same comment on prior
> >> patch.
> >
> > Is this naming a big enough concern to block this series with two
> > explicit acks on this patch that fixes a wholly broken and useless
> > binding?
>
> It is if it comes from one of the DT maintainers.
>
> > I am trying to put out this dumpster fire of a downstream turd that
> > made its way into mainline as the review process has been completely
> > subverted, and is only getting worse with each passing month
>
> This has to stop. Please read Documentation/process/code-of-conduct.rst.
>
>
I apologise for my tone, it's my frustration getting the better of me.
I'll be handing off this series to someone else, so you won't have to
deal with me anymore.
I do ask however that you don't apply patches from MediaTek blindly;
if there's code to read an OF property, and that OF property is not
in the binding, then the patch should be rejected, even if there's an
Ack from the MediaTek maintainer.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v2 phy-next 14/24] phy: introduce phy_get_max_link_rate() helper for consumers
From: Markus Schneider-Pargmann @ 2026-03-09 9:18 UTC (permalink / raw)
To: vladimir.oltean, linux-phy
Cc: Vinod Koul, Neil Armstrong, dri-devel, freedreno,
linux-arm-kernel, linux-arm-msm, linux-can, linux-gpio, linux-ide,
linux-kernel, linux-media, linux-pci, linux-renesas-soc,
linux-riscv, linux-rockchip, linux-samsung-soc, linux-sunxi,
linux-tegra, linux-usb, netdev, spacemit, UNGLinuxDriver,
Andrzej Hajda, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Andy Yan,
Marc Kleine-Budde, Vincent Mailhol, Nicolas Ferre,
Alexandre Belloni, Claudiu Beznea, Markus Schneider-Pargmann,
Geert Uytterhoeven, Magnus Damm
In-Reply-To: <20260308114009.2546587-15-vladimir.oltean@nxp.com>
[-- Attachment #1.1: Type: text/plain, Size: 8081 bytes --]
Hi,
On Sun Mar 8, 2026 at 12:39 PM CET, vladimir.oltean wrote:
> Consumer drivers shouldn't dereference struct phy, not even to get to
> its attributes.
>
> We have phy_get_bus_width() as a precedent for getting the bus_width
> attribute, so let's add phy_get_max_link_rate() and use it in DRM and
> CAN drivers.
>
> In CAN drivers, the transceiver is acquired through devm_phy_optional_get()
> and NULL is given by the API as a non-error case, so the PHY API should
> also tolerate NULL coming back to it. This means we can further simplify
> the call sites that test for the NULL quality of the transceiver.
Thanks for adding this.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> Cc: Andrzej Hajda <andrzej.hajda@intel.com>
> Cc: Neil Armstrong <neil.armstrong@linaro.org>
> Cc: Robert Foss <rfoss@kernel.org>
> Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
> Cc: Jonas Karlman <jonas@kwiboo.se>
> Cc: Jernej Skrabec <jernej.skrabec@gmail.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: David Airlie <airlied@gmail.com>
> Cc: Simona Vetter <simona@ffwll.ch>
> Cc: Andy Yan <andy.yan@rock-chips.com>
> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> Cc: Vincent Mailhol <mailhol@kernel.org>
> Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
> Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Cc: Claudiu Beznea <claudiu.beznea@tuxon.dev>
> Cc: Markus Schneider-Pargmann <msp@baylibre.com>
> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
> Cc: Magnus Damm <magnus.damm@gmail.com>
>
> v1->v2: make phy_get_bus_width() NULL-tolerant to simplify CAN callers
> ---
> drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 4 ++--
> drivers/gpu/drm/bridge/synopsys/dw-dp.c | 2 +-
> drivers/net/can/at91_can.c | 3 +--
> drivers/net/can/flexcan/flexcan-core.c | 3 +--
> drivers/net/can/m_can/m_can_platform.c | 3 +--
For m_can:
Acked-by: Markus Schneider-Pargmann <msp@baylibre.com>
Best
Markus
> drivers/net/can/rcar/rcar_canfd.c | 3 +--
> drivers/phy/phy-core.c | 9 +++++++++
> include/linux/phy/phy.h | 6 ++++++
> 8 files changed, 22 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
> index a8b6ae58cb0a..ed7ed82ddb64 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
> @@ -1300,7 +1300,7 @@ static u32 cdns_mhdp_get_training_interval_us(struct cdns_mhdp_device *mhdp,
>
> static void cdns_mhdp_fill_host_caps(struct cdns_mhdp_device *mhdp)
> {
> - unsigned int link_rate;
> + u32 link_rate;
>
> /* Get source capabilities based on PHY attributes */
>
> @@ -1308,7 +1308,7 @@ static void cdns_mhdp_fill_host_caps(struct cdns_mhdp_device *mhdp)
> if (!mhdp->host.lanes_cnt)
> mhdp->host.lanes_cnt = 4;
>
> - link_rate = mhdp->phy->attrs.max_link_rate;
> + link_rate = phy_get_max_link_rate(mhdp->phy);
> if (!link_rate)
> link_rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_8_1);
> else
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
> index 4ab6922dd79c..79c72ee8e263 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
> @@ -536,7 +536,7 @@ static int dw_dp_link_parse(struct dw_dp *dp, struct drm_connector *connector)
>
> link->revision = link->dpcd[DP_DPCD_REV];
> link->rate = min_t(u32, min(dp->plat_data.max_link_rate,
> - dp->phy->attrs.max_link_rate * 100),
> + phy_get_max_link_rate(dp->phy) * 100),
> drm_dp_max_link_rate(link->dpcd));
> link->lanes = min_t(u8, phy_get_bus_width(dp->phy),
> drm_dp_max_lane_count(link->dpcd));
> diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
> index 58da323f14d7..7749da0a58f6 100644
> --- a/drivers/net/can/at91_can.c
> +++ b/drivers/net/can/at91_can.c
> @@ -1125,8 +1125,7 @@ static int at91_can_probe(struct platform_device *pdev)
>
> can_rx_offload_add_timestamp(dev, &priv->offload);
>
> - if (transceiver)
> - priv->can.bitrate_max = transceiver->attrs.max_link_rate;
> + priv->can.bitrate_max = phy_get_max_link_rate(transceiver);
>
> if (at91_is_sam9263(priv))
> dev->sysfs_groups[0] = &at91_sysfs_attr_group;
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> index f5d22c61503f..093e48b8da58 100644
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
> @@ -2210,8 +2210,7 @@ static int flexcan_probe(struct platform_device *pdev)
> priv->reg_xceiver = reg_xceiver;
> priv->transceiver = transceiver;
>
> - if (transceiver)
> - priv->can.bitrate_max = transceiver->attrs.max_link_rate;
> + priv->can.bitrate_max = phy_get_max_link_rate(transceiver);
>
> if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
> priv->irq_boff = platform_get_irq(pdev, 1);
> diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c
> index 56da411878af..2a0f163a683a 100644
> --- a/drivers/net/can/m_can/m_can_platform.c
> +++ b/drivers/net/can/m_can/m_can_platform.c
> @@ -131,8 +131,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
> goto probe_fail;
> }
>
> - if (transceiver)
> - mcan_class->can.bitrate_max = transceiver->attrs.max_link_rate;
> + mcan_class->can.bitrate_max = phy_get_max_link_rate(transceiver);
>
> priv->base = addr;
> priv->mram_base = mram_addr;
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index eaf8cac78038..9062db48d477 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
> @@ -1884,8 +1884,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
> priv->transceiver = transceiver;
> priv->channel = ch;
> priv->gpriv = gpriv;
> - if (transceiver)
> - priv->can.bitrate_max = transceiver->attrs.max_link_rate;
> + priv->can.bitrate_max = phy_get_max_link_rate(transceiver);
> priv->can.clock.freq = fcan_freq;
> dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq);
>
> diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
> index 0d0be494cfd7..737a760d97d1 100644
> --- a/drivers/phy/phy-core.c
> +++ b/drivers/phy/phy-core.c
> @@ -647,6 +647,15 @@ void phy_set_bus_width(struct phy *phy, int bus_width)
> }
> EXPORT_SYMBOL_GPL(phy_set_bus_width);
>
> +u32 phy_get_max_link_rate(struct phy *phy)
> +{
> + if (!phy)
> + return 0;
> +
> + return phy->attrs.max_link_rate;
> +}
> +EXPORT_SYMBOL_GPL(phy_get_max_link_rate);
> +
> /**
> * _of_phy_get() - lookup and obtain a reference to a phy by phandle
> * @np: device_node for which to get the phy
> diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
> index a7e2432ca1ae..34b656084caf 100644
> --- a/include/linux/phy/phy.h
> +++ b/include/linux/phy/phy.h
> @@ -57,6 +57,7 @@ int phy_notify_disconnect(struct phy *phy, int port);
> int phy_notify_state(struct phy *phy, union phy_notify state);
> int phy_get_bus_width(struct phy *phy);
> void phy_set_bus_width(struct phy *phy, int bus_width);
> +u32 phy_get_max_link_rate(struct phy *phy);
> #else
> static inline struct phy *phy_get(struct device *dev, const char *string)
> {
> @@ -256,6 +257,11 @@ static inline int phy_get_bus_width(struct phy *phy)
> static inline void phy_set_bus_width(struct phy *phy, int bus_width)
> {
> }
> +
> +static inline u32 phy_get_max_link_rate(struct phy *phy)
> +{
> + return 0;
> +}
> #endif /* IS_ENABLED(CONFIG_GENERIC_PHY) */
>
> #endif /* __PHY_CONSUMER_H */
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 289 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCHv2 2/2] phy: miphy28lp: kzalloc + kcalloc to single kzalloc
From: Patrice CHOTARD @ 2026-03-09 7:00 UTC (permalink / raw)
To: Rosen Penev, linux-phy
Cc: Vinod Koul, Neil Armstrong, Kees Cook, Gustavo A. R. Silva,
open list, moderated list:ARM/STI ARCHITECTURE,
open list:KERNEL HARDENING (not covered by other areas):Keyword:b__counted_by(_le|_be)?b
In-Reply-To: <20260306222457.8400-3-rosenp@gmail.com>
On 3/6/26 23:24, Rosen Penev wrote:
> Use flex array to simplify allocation.
>
> Allows using __counted_by for extra runtime analysis.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/phy/st/phy-miphy28lp.c | 12 +++++-------
> 1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c
> index 43cef89af55e..c576fc5569fe 100644
> --- a/drivers/phy/st/phy-miphy28lp.c
> +++ b/drivers/phy/st/phy-miphy28lp.c
> @@ -224,8 +224,8 @@ struct miphy28lp_dev {
> struct device *dev;
> struct regmap *regmap;
> struct mutex miphy_mutex;
> - struct miphy28lp_phy **phys;
> int nphys;
> + struct miphy28lp_phy *phys[] __counted_by(nphys);
> };
>
> enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 };
> @@ -1168,16 +1168,14 @@ static int miphy28lp_probe(struct platform_device *pdev)
> struct phy_provider *provider;
> struct phy *phy;
> int ret, port = 0;
> + size_t nphys;
>
> - miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
> + nphys = of_get_child_count(np);
> + miphy_dev = devm_kzalloc(&pdev->dev, struct_size(miphy_dev, phys, nphys), GFP_KERNEL);
> if (!miphy_dev)
> return -ENOMEM;
>
> - miphy_dev->nphys = of_get_child_count(np);
> - miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
> - sizeof(*miphy_dev->phys), GFP_KERNEL);
> - if (!miphy_dev->phys)
> - return -ENOMEM;
> + miphy_dev->nphys = nphys;
>
> miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
> if (IS_ERR(miphy_dev->regmap)) {
> --
> 2.53.0
>
Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
Thanks
Patrice
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCHv2 1/2] phy: miphy28lp: add COMPILE_TEST
From: Patrice CHOTARD @ 2026-03-09 6:49 UTC (permalink / raw)
To: Rosen Penev, linux-phy
Cc: Vinod Koul, Neil Armstrong, Kees Cook, Gustavo A. R. Silva,
open list, moderated list:ARM/STI ARCHITECTURE,
open list:KERNEL HARDENING (not covered by other areas):Keyword:b__counted_by(_le|_be)?b
In-Reply-To: <20260306222457.8400-2-rosenp@gmail.com>
On 3/6/26 23:24, Rosen Penev wrote:
> There's nothing special here to prevent compilation on non ARM hosts.
>
> Matches every other st phy driver.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/phy/st/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig
> index 304614b6dabf..49206185e563 100644
> --- a/drivers/phy/st/Kconfig
> +++ b/drivers/phy/st/Kconfig
> @@ -4,7 +4,7 @@
> #
> config PHY_MIPHY28LP
> tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407"
> - depends on ARCH_STI
> + depends on ARCH_STI || COMPILE_TEST
> select GENERIC_PHY
> help
> Enable this to support the miphy transceiver (for SATA/PCIE/USB3)
> --
> 2.53.0
>
Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
Thanks
Patrice
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox