* [PATCH v6 phy-next 28/28] MAINTAINERS: add regexes for linux-phy
From: Vladimir Oltean @ 2026-03-27 18:47 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, Joe Perches
In-Reply-To: <20260327184706.1600329-1-vladimir.oltean@nxp.com>
Some pragmatic shortcuts are being taken by PHY consumer driver authors,
which put a burden on the framework. A lot of these can be caught during
review.
Make sure the linux-phy list is copied on as many keywords that regexes
can reasonably catch.
Some considerations that led to this solution and not a simpler one:
- Consumers may be located anywhere, and their file naming provides no
indication whatsoever that they are PHY API consumers.
- The network PHY API has similarly sounding API: phy_start(),
phy_connect(), etc. Similarly, matching on "phy" would hit
phys_addr_t, "cryptography", etc.
- The header files themselves need attention to avoid matching on
include/linux/phy.h (network PHY), include/linux/usb/phy.h,
drivers/net/vendor/device/phy.h, etc.
- At least for a transitional period, I suppose developers will still
try to add PHY providers outside the subsystem (which is discouraged).
So I used \b to try to match on actual word boundaries and I went for
listing all markers of PHY API use as they may appear in patch contexts.
Bit rot is a valid concern. I will add a test to the build automation
that newly introduced struct and function names in include/linux/phy.h,
include/linux/phy-props.h and drivers/phy/phy-provider.h are matched by
the MAINTAINERS entry K: patterns.
The keyword patterns were written with great help from Joe Perches
<joe@perches.com>.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Cc: Joe Perches <joe@perches.com>
v3->v6: none
v2->v3:
- escape forward slash in linux/phy/phy.h in regex pattern:
https://lore.kernel.org/linux-phy/9fd14d166e860f26febfbc9061a6dcae6a166961.camel@perches.com/
v1->v2:
- split into multiple regex patterns
- use matching-only (insted of capturing) regex patterns
- adjust commit message to reflect the Q&A from v1
---
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 55af015174a5..cd920f14abde 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10713,6 +10713,17 @@ F: Documentation/devicetree/bindings/phy/
F: drivers/phy/
F: include/dt-bindings/phy/
F: include/linux/phy/
+K: (?:linux\/phy\/phy\.h|phy-props\.h|phy-provider\.h)
+K: \b(?:__)?(?:devm_)?(?:of_)?phy_(?:create|destroy|provider_(?:un)?register)\b
+K: \bphy_(?:create|remove)_lookup\b
+K: \bphy_(?:get|set)_drvdata\b
+K: \b(?:devm_)?(?:of_)?phy_(?:optional_)?(?:get|put)(?:_by_index)?\b
+K: \bphy_pm_runtime_(?:get|put)(?:_sync)?\b
+K: \bphy_(?:init|exit|power_(?:on|off))\b
+K: \bphy_(?:get|set)_(?:mode(?:_ext)?|media|speed|bus_width|max_link_rate)\b
+K: \bphy_(?:reset|configure|validate|calibrate)\b
+K: \bphy_notify_(?:connect|disconnect|state)\b
+K: \bstruct\s+phy(?:_ops|_attrs|_lookup|_provider)?\b
GENERIC PINCTRL I2C DEMULTIPLEXER DRIVER
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 phy-next 26/28] phy: include PHY provider header (2/2)
From: Vladimir Oltean @ 2026-03-27 18:47 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, Dmitry Baryshkov, Shawn Lin
In-Reply-To: <20260327184706.1600329-1-vladimir.oltean@nxp.com>
The majority of PHY drivers are PHY providers (obviously).
Some are chained PHY provider+consumer (phy-qcom-m31-eusb2.c,
phy-exynos5-usbdrd.c).
Others include <linux/phy/phy.h> because they call consumer functions
such as phy_pm_runtime_get() - phy-mapphone-mdm6600.c. See commit
2ad2af081622 ("phy: mapphone-mdm6600: Improve phy related runtime PM
calls") for the story behind that. My understanding is it's a pragmatic
shortcut, but it doesn't bother much.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> #phy/qualcomm
Acked-by: Shawn Lin <shawn.lin@rock-chips.com>
---
Conflicts in drivers/phy/spacemit/phy-k1-pcie.c with commit 75fb1a33f9ac
("phy: move spacemit pcie driver to its subfolder"). The recommendation
is to patch drivers/phy/phy-spacemit-k1-pcie.c with the change found
here, in order for the branch to build cleanly on top of v7.0-rc1.
Then remember to patch back drivers/phy/spacemit/phy-k1-pcie.c during
the merge to linux-phy/next. VERY IMPORTANT: on v7.0-rc1, the header
path is "phy-provider.h", whereas in phy-next it is "../phy-provider.h",
due to the spacemit folder move.
Conflicts trivially in drivers/phy/qualcomm/phy-qcom-sgmii-eth.c with
commit 4ff5801f45b4 ("phy: qcom-sgmii-eth: add .set_mode() and
.validate() methods").
The recommended resolution is to keep their newly introduced adjacent
line ("+#include <linux/phy.h>" - network PHY) while removing our
"#include <linux/phy/phy.h>" - generic PHY.
This was previously brought up here:
https://lore.kernel.org/netdev/aa1lIBO3j_apIPjb@shell.armlinux.org.uk/
v4->v6: none
v3->v4:
- fix phy-provider.h path from drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
- make sure include/linux/phy/tegra/xusb.h is not reliant upon an
external "struct phy" definition
v2->v3: none
v1->v2: split in two parts to pass through linux-phy mailing list
moderation. The split is at letter 'q' (Qualcomm)
---
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 ++-
drivers/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 | 3 ++-
drivers/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 ++-
drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 3 ++-
drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 3 ++-
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 3 ++-
drivers/phy/qualcomm/phy-qcom-qusb2.c | 4 ++--
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 3 ++-
drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c | 3 ++-
drivers/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 | 3 ++-
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 | 3 ++-
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 ++-
drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 3 ++-
drivers/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 ++-
drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 3 ++-
drivers/phy/rockchip/phy-rockchip-pcie.c | 2 +-
drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c | 3 ++-
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 ++
drivers/phy/rockchip/phy-rockchip-snps-pcie3.c | 3 ++-
drivers/phy/rockchip/phy-rockchip-typec.c | 4 ++--
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 | 3 ++-
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-twl4030-usb.c | 3 ++-
drivers/phy/xilinx/phy-zynqmp.c | 4 ++--
include/linux/phy/phy-sun4i-usb.h | 2 +-
include/linux/phy/tegra/xusb.h | 1 +
include/linux/phy/ulpi_phy.h | 2 +-
98 files changed, 187 insertions(+), 96 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c
index f8d0199c6e78..2f07241be600 100644
--- a/drivers/phy/qualcomm/phy-ath79-usb.c
+++ b/drivers/phy/qualcomm/phy-ath79-usb.c
@@ -8,9 +8,10 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/phy/phy.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
struct ath79_usb_phy {
struct reset_control *reset;
/* The suspend override logic is inverted, hence the no prefix
diff --git a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
index cae290a6e19f..dd73ecbb6c1e 100644
--- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
+++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
@@ -13,7 +13,8 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <linux/phy/phy.h>
+
+#include "../phy-provider.h"
/* PHY registers */
#define UNIPHY_PLL_REFCLK_CFG 0x000
diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
index 7372de05a0b8..faddba0f20c7 100644
--- a/drivers/phy/qualcomm/phy-qcom-edp.c
+++ b/drivers/phy/qualcomm/phy-qcom-edp.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/phy/phy-dp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -22,6 +21,8 @@
#include <dt-bindings/phy/phy.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-dp-phy.h"
#include "phy-qcom-qmp-qserdes-com-v4.h"
#include "phy-qcom-qmp-qserdes-com-v6.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
index efeec4709a15..5783bdabc287 100644
--- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
@@ -8,7 +8,8 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
+
+#include "../phy-provider.h"
/* eUSB2 status registers */
#define EUSB2_RPTR_STATUS 0x08
diff --git a/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
index da6f290af722..f1c1c2969e37 100644
--- a/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
@@ -14,10 +14,11 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
struct ipq4019_usb_phy {
struct device *dev;
struct phy *phy;
diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
index f5eb0bdac418..d5407784c18f 100644
--- a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
+++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
@@ -13,7 +13,8 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <linux/phy/phy.h>
+
+#include "../phy-provider.h"
struct qcom_ipq806x_sata_phy {
void __iomem *mmio;
diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c
index f22c0000479f..54144f0547f0 100644
--- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c
@@ -5,13 +5,14 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/bitfield.h>
+#include "../phy-provider.h"
+
/* USB QSCRATCH Hardware registers */
#define QSCRATCH_GENERAL_CFG (0x08)
#define HSUSB_PHY_CTRL_REG (0x10)
diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c
index 68f1ba8fec4a..9e3a911023cd 100644
--- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c
@@ -18,6 +18,8 @@
#include <linux/regulator/consumer.h>
+#include "../phy-provider.h"
+
#define USB_PHY_UTMI_CTRL0 (0x3c)
#define SLEEPM BIT(0)
diff --git a/drivers/phy/qualcomm/phy-qcom-m31.c b/drivers/phy/qualcomm/phy-qcom-m31.c
index 168ea980fda0..1a63a5807d37 100644
--- a/drivers/phy/qualcomm/phy-qcom-m31.c
+++ b/drivers/phy/qualcomm/phy-qcom-m31.c
@@ -10,11 +10,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#define USB2PHY_PORT_UTMI_CTRL1 0x40
#define USB2PHY_PORT_UTMI_CTRL2 0x44
diff --git a/drivers/phy/qualcomm/phy-qcom-pcie2.c b/drivers/phy/qualcomm/phy-qcom-pcie2.c
index 11a2bb958681..4c74d8e7722d 100644
--- a/drivers/phy/qualcomm/phy-qcom-pcie2.c
+++ b/drivers/phy/qualcomm/phy-qcom-pcie2.c
@@ -8,11 +8,12 @@
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#include <dt-bindings/phy/phy.h>
#define PCIE20_PARF_PHY_STTS 0x3c
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index b9ea7d058e93..04c54c229f08 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -14,7 +14,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -28,6 +27,8 @@
#include <dt-bindings/phy/phy-qcom-qmp.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
index a7c65cfe31df..df38d5b6d5be 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
@@ -13,12 +13,13 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index fed2fc9bb311..06680151360e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -15,7 +15,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/pcie.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -24,6 +23,8 @@
#include <dt-bindings/phy/phy-qcom-qmp.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index df138a5442eb..75cd5b10fdb2 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -21,6 +20,8 @@
#include <ufs/unipro.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c
index 2bd5862c5ba8..a682b30db03e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c
@@ -14,13 +14,14 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp.h"
#include "phy-qcom-qmp-pcs-misc-v3.h"
#include "phy-qcom-qmp-pcs-usb-v4.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index d88b8a415e85..3db0a5282dbf 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -13,13 +13,14 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index f62e1f6ecc07..b77007f8fee3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -25,6 +24,8 @@
#include <linux/usb/typec_mux.h>
#include <dt-bindings/phy/phy-qcom-qmp.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 191040f6d60f..e5516099b911 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -3,6 +3,7 @@
* Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
*/
+#include <dt-bindings/phy/phy-qcom-qusb2.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -12,7 +13,6 @@
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -20,7 +20,7 @@
#include <linux/reset.h>
#include <linux/slab.h>
-#include <dt-bindings/phy/phy-qcom-qusb2.h>
+#include "../phy-provider.h"
#define QUSB2PHY_PLL 0x0
#define QUSB2PHY_PLL_TEST 0x04
diff --git a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c
index 5b1c82459c12..4f8ffc6524ab 100644
--- a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c
+++ b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c
@@ -7,10 +7,11 @@
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#include "phy-qcom-qmp-pcs-sgmii.h"
#include "phy-qcom-qmp-qserdes-com-v5.h"
#include "phy-qcom-qmp-qserdes-txrx-v5.h"
diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
index 8915fa250e81..17a33e545008 100644
--- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
+++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -18,6 +17,8 @@
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#define USB2_PHY_USB_PHY_UTMI_CTRL0 (0x3c)
#define SLEEPM BIT(0)
#define OPMODE_MASK GENMASK(4, 3)
diff --git a/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
index 324c0a5d658e..13828d4f788e 100644
--- a/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
+++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
@@ -12,12 +12,13 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/units.h>
+#include "../phy-provider.h"
+
#define RST_ASSERT_DELAY_MIN_US 100
#define RST_ASSERT_DELAY_MAX_US 150
#define PIPE_CLK_DELAY_MIN_US 5000
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
index a52a9bf13b75..ce317deaeacb 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
@@ -11,12 +11,13 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
/* PHY register and bit definitions */
#define PHY_CTRL_COMMON0 0x078
#define SIDDQ BIT(2)
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
index 98a18987f1be..95581926023f 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
@@ -8,11 +8,12 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/reset.h>
#include <linux/extcon.h>
#include <linux/notifier.h>
+#include "../phy-provider.h"
+
#define ULPI_PWR_CLK_MNG_REG 0x88
# define ULPI_PWR_OTG_COMP_DISABLE BIT(0)
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
index 20f6dd37c7c1..fe9315a2f207 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
@@ -5,12 +5,13 @@
#include <linux/module.h>
#include <linux/ulpi/driver.h>
#include <linux/ulpi/regs.h>
-#include <linux/phy/phy.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl-state.h>
#include <linux/delay.h>
#include <linux/clk.h>
+#include "../phy-provider.h"
+
#define ULPI_HSIC_CFG 0x30
#define ULPI_HSIC_IO_CAL 0x33
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-ss.c b/drivers/phy/qualcomm/phy-qcom-usb-ss.c
index a3a6d3ce7ea1..17ca14a0b34d 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-ss.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-ss.c
@@ -11,12 +11,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#define PHY_CTRL0 0x6C
#define PHY_CTRL1 0x70
#define PHY_CTRL2 0x74
diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c
index a591ad95347c..4865a264136d 100644
--- a/drivers/phy/ralink/phy-mt7621-pci.c
+++ b/drivers/phy/ralink/phy-mt7621-pci.c
@@ -10,11 +10,12 @@
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sys_soc.h>
+#include "../phy-provider.h"
+
#define RG_PE1_PIPE_REG 0x02c
#define RG_PE1_PIPE_RST BIT(12)
#define RG_PE1_PIPE_CMD_FRC BIT(4)
diff --git a/drivers/phy/ralink/phy-ralink-usb.c b/drivers/phy/ralink/phy-ralink-usb.c
index 0ff07e210769..cc61139ce157 100644
--- a/drivers/phy/ralink/phy-ralink-usb.c
+++ b/drivers/phy/ralink/phy-ralink-usb.c
@@ -14,11 +14,12 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define RT_SYSC_REG_SYSCFG1 0x014
#define RT_SYSC_REG_CLKCFG1 0x030
#define RT_SYSC_REG_USB_PHY_CFG 0x05c
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
index 248550ef98ca..a0431f11972e 100644
--- a/drivers/phy/realtek/phy-rtk-usb2.c
+++ b/drivers/phy/realtek/phy-rtk-usb2.c
@@ -16,9 +16,10 @@
#include <linux/regmap.h>
#include <linux/sys_soc.h>
#include <linux/mfd/syscon.h>
-#include <linux/phy/phy.h>
#include <linux/usb.h>
+#include "../phy-provider.h"
+
/* GUSB2PHYACCn register */
#define PHY_NEW_REG_REQ BIT(25)
#define PHY_VSTS_BUSY BIT(23)
diff --git a/drivers/phy/realtek/phy-rtk-usb3.c b/drivers/phy/realtek/phy-rtk-usb3.c
index cce453686db2..3f565c4d96be 100644
--- a/drivers/phy/realtek/phy-rtk-usb3.c
+++ b/drivers/phy/realtek/phy-rtk-usb3.c
@@ -16,9 +16,10 @@
#include <linux/regmap.h>
#include <linux/sys_soc.h>
#include <linux/mfd/syscon.h>
-#include <linux/phy/phy.h>
#include <linux/usb.h>
+#include "../phy-provider.h"
+
#define USB_MDIO_CTRL_PHY_BUSY BIT(7)
#define USB_MDIO_CTRL_PHY_WRITE BIT(0)
#define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c
index 6c671254c625..ca5498986120 100644
--- a/drivers/phy/renesas/phy-rcar-gen2.c
+++ b/drivers/phy/renesas/phy-rcar-gen2.c
@@ -12,11 +12,12 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
+#include "../phy-provider.h"
+
#define USBHS_LPSTS 0x02
#define USBHS_UGCTRL 0x80
#define USBHS_UGCTRL2 0x84
diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c
index 3e2cf59ad480..747a1cd74639 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c
@@ -9,11 +9,12 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
+#include "../phy-provider.h"
+
#define PHY_CTRL 0x4000 /* R8A77980 only */
/* PHY control register (PHY_CTRL) */
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index cfc2a8d9028d..48ae5a507752 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -19,7 +19,6 @@
#include <linux/mutex.h>
#include <linux/mux/consumer.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -29,6 +28,8 @@
#include <linux/usb/of.h>
#include <linux/workqueue.h>
+#include "../phy-provider.h"
+
/******* USB2.0 Host registers (original offset is +0x200) *******/
#define USB2_INT_ENABLE 0x000
#define USB2_AHB_BUS_CTR 0x008
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c
index 0420f5b283ce..3511831e95d2 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c
@@ -10,10 +10,11 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include "../phy-provider.h"
+
#define USB30_CLKSET0 0x034
#define USB30_CLKSET1 0x036
#define USB30_SSC_SET 0x038
diff --git a/drivers/phy/renesas/phy-rzg3e-usb3.c b/drivers/phy/renesas/phy-rzg3e-usb3.c
index 6b3453ea0004..1c9e2276bb73 100644
--- a/drivers/phy/renesas/phy-rzg3e-usb3.c
+++ b/drivers/phy/renesas/phy-rzg3e-usb3.c
@@ -11,11 +11,12 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define USB3_TEST_RESET 0x0000
#define USB3_TEST_UTMICTRL2 0x0b04
#define USB3_TEST_PRMCTRL5_R 0x0c10
diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c
index c34427ac4fdb..807af518aeda 100644
--- a/drivers/phy/renesas/r8a779f0-ether-serdes.c
+++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c
@@ -10,11 +10,12 @@
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/phy.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define R8A779F0_ETH_SERDES_NUM 3
#define R8A779F0_ETH_SERDES_OFFSET 0x0400
#define R8A779F0_ETH_SERDES_BANK_SELECT 0x03fc
diff --git a/drivers/phy/rockchip/phy-rockchip-dp.c b/drivers/phy/rockchip/phy-rockchip-dp.c
index 592aa956eead..63e972969379 100644
--- a/drivers/phy/rockchip/phy-rockchip-dp.c
+++ b/drivers/phy/rockchip/phy-rockchip-dp.c
@@ -10,10 +10,11 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define GRF_SOC_CON12 0x0274
#define GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK BIT(20)
diff --git a/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c b/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c
index e6a768bbb9b3..de7e00580e20 100644
--- a/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c
+++ b/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c
@@ -21,11 +21,12 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define RK3399_GRF_SOC_CON9 0x6224
#define RK3399_GRF_SOC_CON21 0x6254
#define RK3399_GRF_SOC_CON22 0x6258
diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c
index 5187983c58e5..fd292f063f48 100644
--- a/drivers/phy/rockchip/phy-rockchip-emmc.c
+++ b/drivers/phy/rockchip/phy-rockchip-emmc.c
@@ -13,10 +13,11 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
/*
* The higher 16-bit of this register is used for write protection
* only if BIT(x + 16) set to 1 the BIT(x) can be written.
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
index c79fb53d8ee5..3b5d86b07564 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
@@ -13,13 +13,14 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
/* GRF */
#define RK1808_GRF_PD_VI_CON_OFFSET 0x0430
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
index 30d5e5ddff4a..5613b34958fe 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
@@ -15,13 +15,13 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/phy/phy-mipi-dphy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/time64.h>
-#include <linux/phy/phy.h>
-#include <linux/phy/phy-mipi-dphy.h>
+#include "../phy-provider.h"
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index 1483907413fa..82b5e7434f83 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -20,6 +20,8 @@
#include <linux/phy/phy.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
/* REG: 0x00 */
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 8f4c08e599aa..f88e09f61994 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -18,7 +18,6 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
@@ -27,6 +26,8 @@
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
+#include "../phy-provider.h"
+
#define BIT_WRITEABLE_SHIFT 16
#define SCHEDULE_DELAY (60 * HZ)
#define OTG_SCHEDULE_DELAY (2 * HZ)
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index b60d6bf3f33c..2deb2666acb1 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -9,12 +9,13 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/units.h>
+#include "../phy-provider.h"
+
#define BIT_WRITEABLE_SHIFT 16
#define REF_CLOCK_24MHz (24 * HZ_PER_MHZ)
#define REF_CLOCK_25MHz (25 * HZ_PER_MHZ)
diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c
index 126306c01454..604ff00653b0 100644
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -13,12 +13,12 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
#define PHY_MAX_LANE_NUM 4
#define PHY_CFG_DATA_MASK GENMASK(10, 7)
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
index 0f69060aa5d5..78a0446b81df 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
@@ -15,12 +15,13 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define BIAS_CON0 0x0000
#define I_RES_CNTL_MASK GENMASK(6, 4)
#define I_RES_CNTL(x) FIELD_PREP(I_RES_CNTL_MASK, x)
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 2d973bc37f07..01801a4dc436 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -21,6 +21,8 @@
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define GRF_HDPTX_CON0 0x00
#define LC_REF_CLK_SEL BIT(11)
#define HDPTX_I_PLL_EN BIT(7)
diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
index 4e8ffd173096..029566330aa0 100644
--- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
+++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
@@ -14,11 +14,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/pcie.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
/* Register for RK3568 */
#define GRF_PCIE30PHY_CON1 0x4
#define GRF_PCIE30PHY_CON6 0x18
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 0a318ccf1bbf..4a9756ca4f68 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -43,6 +43,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
@@ -53,8 +54,7 @@
#include <linux/regmap.h>
#include <linux/reset.h>
-#include <linux/mfd/syscon.h>
-#include <linux/phy/phy.h>
+#include "../phy-provider.h"
#define CMN_SSM_BANDGAP (0x21 << 2)
#define CMN_SSM_BIAS (0x22 << 2)
diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c
index cef96739cf3f..0652f821332b 100644
--- a/drivers/phy/rockchip/phy-rockchip-usb.c
+++ b/drivers/phy/rockchip/phy-rockchip-usb.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -23,6 +22,8 @@
#include <linux/mfd/syscon.h>
#include <linux/delay.h>
+#include "../phy-provider.h"
+
static int enable_usb_uart;
#define UOC_CON0 0x00
diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index fba35510d88c..cf2abf29512f 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -25,6 +25,8 @@
#include <linux/usb/typec_dp.h>
#include <linux/usb/typec_mux.h>
+#include "../phy-provider.h"
+
/* USBDP PHY Register Definitions */
#define UDPHY_PCS 0x4000
#define UDPHY_PMA 0x8000
diff --git a/drivers/phy/samsung/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c
index a636dee07585..00d0ed82a620 100644
--- a/drivers/phy/samsung/phy-exynos-dp-video.c
+++ b/drivers/phy/samsung/phy-exynos-dp-video.c
@@ -12,11 +12,12 @@
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
+#include "../phy-provider.h"
+
struct exynos_dp_video_phy_drvdata {
u32 phy_ctrl_offset;
};
diff --git a/drivers/phy/samsung/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c
index be925508ed97..ce8a258a104e 100644
--- a/drivers/phy/samsung/phy-exynos-mipi-video.c
+++ b/drivers/phy/samsung/phy-exynos-mipi-video.c
@@ -11,13 +11,14 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/mfd/syscon.h>
+#include "../phy-provider.h"
+
enum exynos_mipi_phy_id {
EXYNOS_MIPI_PHY_ID_NONE = -1,
EXYNOS_MIPI_PHY_ID_CSIS0,
diff --git a/drivers/phy/samsung/phy-exynos-pcie.c b/drivers/phy/samsung/phy-exynos-pcie.c
index 53c9230c2907..9dd3a4a90fa7 100644
--- a/drivers/phy/samsung/phy-exynos-pcie.c
+++ b/drivers/phy/samsung/phy-exynos-pcie.c
@@ -12,9 +12,10 @@
#include <linux/mfd/syscon.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define PCIE_PHY_OFFSET(x) ((x) * 0x4)
/* Sysreg FSYS register offsets and bits for Exynos5433 */
diff --git a/drivers/phy/samsung/phy-exynos4210-usb2.c b/drivers/phy/samsung/phy-exynos4210-usb2.c
index 3898a7f58217..beb2f96bebbf 100644
--- a/drivers/phy/samsung/phy-exynos4210-usb2.c
+++ b/drivers/phy/samsung/phy-exynos4210-usb2.c
@@ -8,8 +8,9 @@
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
+
+#include "../phy-provider.h"
#include "phy-samsung-usb2.h"
/* Exynos USB PHY registers */
diff --git a/drivers/phy/samsung/phy-exynos4x12-usb2.c b/drivers/phy/samsung/phy-exynos4x12-usb2.c
index b528a5d037fe..a402f80d0aab 100644
--- a/drivers/phy/samsung/phy-exynos4x12-usb2.c
+++ b/drivers/phy/samsung/phy-exynos4x12-usb2.c
@@ -8,8 +8,9 @@
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
+
+#include "../phy-provider.h"
#include "phy-samsung-usb2.h"
/* Exynos USB PHY registers */
diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
index 5a181cb4597e..cb476d007e3f 100644
--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
+++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
@@ -26,6 +26,8 @@
#include <linux/usb/typec.h>
#include <linux/usb/typec_mux.h>
+#include "../phy-provider.h"
+
/* Exynos USB PHY registers */
#define EXYNOS5_FSEL_9MHZ6 0x0
#define EXYNOS5_FSEL_10MHZ 0x1
diff --git a/drivers/phy/samsung/phy-exynos5250-sata.c b/drivers/phy/samsung/phy-exynos5250-sata.c
index 595adba5fb8f..0f85ae0a5901 100644
--- a/drivers/phy/samsung/phy-exynos5250-sata.c
+++ b/drivers/phy/samsung/phy-exynos5250-sata.c
@@ -15,12 +15,13 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/mfd/syscon.h>
+#include "../phy-provider.h"
+
#define SATAPHY_CONTROL_OFFSET 0x0724
#define EXYNOS5_SATAPHY_PMU_ENABLE BIT(0)
#define EXYNOS5_SATA_RESET 0x4
diff --git a/drivers/phy/samsung/phy-exynos5250-usb2.c b/drivers/phy/samsung/phy-exynos5250-usb2.c
index 21b06072f866..04815633f290 100644
--- a/drivers/phy/samsung/phy-exynos5250-usb2.c
+++ b/drivers/phy/samsung/phy-exynos5250-usb2.c
@@ -8,8 +8,9 @@
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
+
+#include "../phy-provider.h"
#include "phy-samsung-usb2.h"
/* Exynos USB PHY registers */
diff --git a/drivers/phy/samsung/phy-s5pv210-usb2.c b/drivers/phy/samsung/phy-s5pv210-usb2.c
index 32be62e49804..4d72559d29a9 100644
--- a/drivers/phy/samsung/phy-s5pv210-usb2.c
+++ b/drivers/phy/samsung/phy-s5pv210-usb2.c
@@ -8,7 +8,8 @@
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/phy/phy.h>
+
+#include "../phy-provider.h"
#include "phy-samsung-usb2.h"
/* Exynos USB PHY registers */
diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c
index ee665f26c236..b55a726cd44e 100644
--- a/drivers/phy/samsung/phy-samsung-ufs.c
+++ b/drivers/phy/samsung/phy-samsung-ufs.c
@@ -15,10 +15,10 @@
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
#include "phy-samsung-ufs.h"
#define for_each_phy_lane(phy, i) \
diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h
index f2c2e744e5ba..90f4d4cef631 100644
--- a/drivers/phy/samsung/phy-samsung-ufs.h
+++ b/drivers/phy/samsung/phy-samsung-ufs.h
@@ -10,9 +10,10 @@
#ifndef _PHY_SAMSUNG_UFS_
#define _PHY_SAMSUNG_UFS_
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define PHY_COMN_BLK 1
#define PHY_TRSV_BLK 2
#define END_UFS_PHY_CFG { 0 }
diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c
index d2749b67cf8f..362dd4ae3cab 100644
--- a/drivers/phy/samsung/phy-samsung-usb2.c
+++ b/drivers/phy/samsung/phy-samsung-usb2.c
@@ -13,6 +13,8 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+
+#include "../phy-provider.h"
#include "phy-samsung-usb2.h"
static int samsung_usb2_phy_power_on(struct phy *phy)
diff --git a/drivers/phy/samsung/phy-samsung-usb2.h b/drivers/phy/samsung/phy-samsung-usb2.h
index ebaf43bfc5a2..515c7938fccd 100644
--- a/drivers/phy/samsung/phy-samsung-usb2.h
+++ b/drivers/phy/samsung/phy-samsung-usb2.h
@@ -10,12 +10,13 @@
#define _PHY_EXYNOS_USB2_H
#include <linux/clk.h>
-#include <linux/phy/phy.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/regulator/consumer.h>
+#include "../phy-provider.h"
+
#define KHZ 1000
#define MHZ (KHZ * KHZ)
diff --git a/drivers/phy/socionext/phy-uniphier-ahci.c b/drivers/phy/socionext/phy-uniphier-ahci.c
index 28cf3efe0695..6b3ce56c7f0c 100644
--- a/drivers/phy/socionext/phy-uniphier-ahci.c
+++ b/drivers/phy/socionext/phy-uniphier-ahci.c
@@ -12,10 +12,11 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
struct uniphier_ahciphy_priv {
struct device *dev;
void __iomem *base;
diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c
index c19173492b79..00f6cdf846f1 100644
--- a/drivers/phy/socionext/phy-uniphier-pcie.c
+++ b/drivers/phy/socionext/phy-uniphier-pcie.c
@@ -12,12 +12,13 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/resource.h>
+#include "../phy-provider.h"
+
/* PHY */
#define PCL_PHY_CLKCTRL 0x0000
#define PORT_SEL_MASK GENMASK(11, 9)
diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c
index c49d432e526b..6ee566478be0 100644
--- a/drivers/phy/socionext/phy-uniphier-usb2.c
+++ b/drivers/phy/socionext/phy-uniphier-usb2.c
@@ -10,11 +10,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include "../phy-provider.h"
+
#define SG_USBPHY1CTRL 0x500
#define SG_USBPHY1CTRL2 0x504
#define SG_USBPHY2CTRL 0x508
diff --git a/drivers/phy/socionext/phy-uniphier-usb3hs.c b/drivers/phy/socionext/phy-uniphier-usb3hs.c
index 8c8673df0084..a08db863223f 100644
--- a/drivers/phy/socionext/phy-uniphier-usb3hs.c
+++ b/drivers/phy/socionext/phy-uniphier-usb3hs.c
@@ -17,12 +17,13 @@
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
#define HSPHY_CFG0 0x0
#define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28)
#define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26)
diff --git a/drivers/phy/socionext/phy-uniphier-usb3ss.c b/drivers/phy/socionext/phy-uniphier-usb3ss.c
index f402ed8732fd..8829305e9d4c 100644
--- a/drivers/phy/socionext/phy-uniphier-usb3ss.c
+++ b/drivers/phy/socionext/phy-uniphier-usb3ss.c
@@ -16,11 +16,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define SSPHY_TESTI 0x0
#define TESTI_DAT_MASK GENMASK(13, 6)
#define TESTI_ADR_MASK GENMASK(5, 1)
diff --git a/drivers/phy/sophgo/phy-cv1800-usb2.c b/drivers/phy/sophgo/phy-cv1800-usb2.c
index 6fe846534e9c..1fd7bba498ad 100644
--- a/drivers/phy/sophgo/phy-cv1800-usb2.c
+++ b/drivers/phy/sophgo/phy-cv1800-usb2.c
@@ -12,10 +12,11 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
+#include "../phy-provider.h"
+
#define REG_USB_PHY_CTRL 0x048
#define PHY_VBUS_POWER_EN BIT(0)
diff --git a/drivers/phy/spacemit/phy-k1-pcie.c b/drivers/phy/spacemit/phy-k1-pcie.c
index 75477bea7f70..6f8f2f39f7f8 100644
--- a/drivers/phy/spacemit/phy-k1-pcie.c
+++ b/drivers/phy/spacemit/phy-k1-pcie.c
@@ -5,6 +5,7 @@
* Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
*/
+#include <dt-bindings/phy/phy.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
@@ -12,12 +13,11 @@
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
-#include <dt-bindings/phy/phy.h>
+#include "../phy-provider.h"
/*
* Three PCIe ports are supported in the SpacemiT K1 SoC, and this driver
diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
index 14a02f554810..f482b6c9b6d4 100644
--- a/drivers/phy/spacemit/phy-k1-usb2.c
+++ b/drivers/phy/spacemit/phy-k1-usb2.c
@@ -9,11 +9,12 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/usb/of.h>
+#include "../phy-provider.h"
+
#define PHY_RST_MODE_CTRL 0x04
#define PHY_PLL_RDY BIT(0)
#define PHY_CLK_CDR_EN BIT(1)
diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c
index 43cef89af55e..e9792deb629a 100644
--- a/drivers/phy/st/phy-miphy28lp.c
+++ b/drivers/phy/st/phy-miphy28lp.c
@@ -7,6 +7,7 @@
* Author: Alexandre Torgue <alexandre.torgue@st.com>
*/
+#include <dt-bindings/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -16,13 +17,12 @@
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/clk.h>
-#include <linux/phy/phy.h>
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/reset.h>
-#include <dt-bindings/phy/phy.h>
+#include "../phy-provider.h"
/* MiPHY registers */
#define MIPHY_CONF_RESET 0x00
diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c
index c661ab63505f..86acc2412c46 100644
--- a/drivers/phy/st/phy-spear1310-miphy.c
+++ b/drivers/phy/st/phy-spear1310-miphy.c
@@ -14,10 +14,11 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
/* SPEAr1310 Registers */
#define SPEAR1310_PCIE_SATA_CFG 0x3A4
#define SPEAR1310_PCIE_SATA2_SEL_PCIE (0 << 31)
diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c
index 85a60d64ebb7..4dbd3158c060 100644
--- a/drivers/phy/st/phy-spear1340-miphy.c
+++ b/drivers/phy/st/phy-spear1340-miphy.c
@@ -14,10 +14,11 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
/* SPEAr1340 Registers */
/* Power Management Registers */
#define SPEAR1340_PCM_CFG 0x100
diff --git a/drivers/phy/st/phy-stih407-usb.c b/drivers/phy/st/phy-stih407-usb.c
index 7a3e4584895c..497f9aa4139d 100644
--- a/drivers/phy/st/phy-stih407-usb.c
+++ b/drivers/phy/st/phy-stih407-usb.c
@@ -16,7 +16,8 @@
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/mfd/syscon.h>
-#include <linux/phy/phy.h>
+
+#include "../phy-provider.h"
#define PHYPARAM_REG 0
#define PHYCTRL_REG 1
diff --git a/drivers/phy/st/phy-stm32-combophy.c b/drivers/phy/st/phy-stm32-combophy.c
index 607b4d607eb5..8757b1993e90 100644
--- a/drivers/phy/st/phy-stm32-combophy.c
+++ b/drivers/phy/st/phy-stm32-combophy.c
@@ -10,12 +10,13 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
-#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <dt-bindings/phy/phy.h>
+#include "../phy-provider.h"
+
#define SYSCFG_COMBOPHY_CR1 0x4c00
#define SYSCFG_COMBOPHY_CR2 0x4c04
#define SYSCFG_COMBOPHY_CR4 0x4c0c
diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
index b44afbff8616..647fbbe5c734 100644
--- a/drivers/phy/st/phy-stm32-usbphyc.c
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -18,6 +18,8 @@
#include <linux/reset.h>
#include <linux/units.h>
+#include "../phy-provider.h"
+
#define STM32_USBPHYC_PLL 0x0
#define STM32_USBPHYC_MISC 0x8
#define STM32_USBPHYC_MONITOR(X) (0x108 + ((X) * 0x100))
diff --git a/drivers/phy/starfive/phy-jh7110-dphy-rx.c b/drivers/phy/starfive/phy-jh7110-dphy-rx.c
index 0b039e1f71c5..099a1ebf6194 100644
--- a/drivers/phy/starfive/phy-jh7110-dphy-rx.c
+++ b/drivers/phy/starfive/phy-jh7110-dphy-rx.c
@@ -13,11 +13,12 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define STF_DPHY_APBCFGSAIF_SYSCFG(x) (x)
#define STF_DPHY_ENABLE_CLK BIT(6)
diff --git a/drivers/phy/starfive/phy-jh7110-dphy-tx.c b/drivers/phy/starfive/phy-jh7110-dphy-tx.c
index c64d1c91b130..a5faf06b6d14 100644
--- a/drivers/phy/starfive/phy-jh7110-dphy-tx.c
+++ b/drivers/phy/starfive/phy-jh7110-dphy-tx.c
@@ -15,12 +15,13 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define STF_DPHY_APBIFSAIF_SYSCFG(x) (x)
#define STF_DPHY_AON_POWER_READY_N_ACTIVE 0
diff --git a/drivers/phy/starfive/phy-jh7110-pcie.c b/drivers/phy/starfive/phy-jh7110-pcie.c
index 734c8e007727..d68d396ac3cc 100644
--- a/drivers/phy/starfive/phy-jh7110-pcie.c
+++ b/drivers/phy/starfive/phy-jh7110-pcie.c
@@ -12,10 +12,11 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mfd/syscon.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define PCIE_KVCO_LEVEL_OFF 0x28
#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c
#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80
diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c
index b505d89860b4..5762586e5c7d 100644
--- a/drivers/phy/starfive/phy-jh7110-usb.c
+++ b/drivers/phy/starfive/phy-jh7110-usb.c
@@ -12,11 +12,12 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/usb/of.h>
+#include "../phy-provider.h"
+
#define USB_125M_CLK_RATE 125000000
#define USB_CLK_MODE_OFF 0x0
#define USB_CLK_MODE_RX_NORMAL_PWR BIT(1)
diff --git a/drivers/phy/sunplus/phy-sunplus-usb2.c b/drivers/phy/sunplus/phy-sunplus-usb2.c
index 637a5fbae6d9..2ddbc37d09ee 100644
--- a/drivers/phy/sunplus/phy-sunplus-usb2.c
+++ b/drivers/phy/sunplus/phy-sunplus-usb2.c
@@ -17,10 +17,11 @@
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
+#include "../phy-provider.h"
+
#define HIGH_MASK_BITS GENMASK(31, 16)
#define LOW_MASK_BITS GENMASK(15, 0)
#define OTP_DISC_LEVEL_DEFAULT 0xd
diff --git a/drivers/phy/tegra/phy-tegra194-p2u.c b/drivers/phy/tegra/phy-tegra194-p2u.c
index f49b417c9eb6..467b6b97e53d 100644
--- a/drivers/phy/tegra/phy-tegra194-p2u.c
+++ b/drivers/phy/tegra/phy-tegra194-p2u.c
@@ -11,9 +11,10 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include "../phy-provider.h"
+
#define P2U_CONTROL_CMN 0x74
#define P2U_CONTROL_CMN_ENABLE_L2_EXIT_RATE_CHANGE BIT(13)
#define P2U_CONTROL_CMN_SKP_SIZE_PROTECTION_EN BIT(20)
diff --git a/drivers/phy/tegra/xusb-tegra124.c b/drivers/phy/tegra/xusb-tegra124.c
index 70b6213370a8..21686c6fb2d7 100644
--- a/drivers/phy/tegra/xusb-tegra124.c
+++ b/drivers/phy/tegra/xusb-tegra124.c
@@ -8,7 +8,6 @@
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -16,6 +15,7 @@
#include <soc/tegra/fuse.h>
+#include "../phy-provider.h"
#include "xusb.h"
#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0)
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
index 1ddf11265974..e017cb1ff484 100644
--- a/drivers/phy/tegra/xusb-tegra186.c
+++ b/drivers/phy/tegra/xusb-tegra186.c
@@ -7,7 +7,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -15,6 +14,7 @@
#include <soc/tegra/fuse.h>
+#include "../phy-provider.h"
#include "xusb.h"
/* FUSE USB_CALIB registers */
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 1abc5913ec49..006aba47b93d 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -21,6 +20,7 @@
#include <soc/tegra/fuse.h>
+#include "../phy-provider.h"
#include "xusb.h"
#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) \
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 9d74c0ecc31b..07a2f5a4dbee 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/phy/phy.h>
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -19,6 +18,7 @@
#include <soc/tegra/fuse.h>
+#include "../phy-provider.h"
#include "xusb.h"
static struct phy *tegra_xusb_pad_of_xlate(struct device *dev,
diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c
index 5b6c27aa7e8b..8990b715525e 100644
--- a/drivers/phy/ti/phy-am654-serdes.c
+++ b/drivers/phy/ti/phy-am654-serdes.c
@@ -15,11 +15,12 @@
#include <linux/mfd/syscon.h>
#include <linux/mux/consumer.h>
#include <linux/of_address.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define CMU_R004 0x4
#define CMU_R060 0x60
#define CMU_R07C 0x7c
diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c
index 62fa6f89c0e6..261b65abd38b 100644
--- a/drivers/phy/ti/phy-da8xx-usb.c
+++ b/drivers/phy/ti/phy-da8xx-usb.c
@@ -11,12 +11,13 @@
#include <linux/mfd/da8xx-cfgchip.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/phy/phy.h>
#include <linux/platform_data/phy-da8xx-usb.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define PHY_INIT_BITS (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN)
struct da8xx_usb_phy {
diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c
index d274831b731c..515ef7812bde 100644
--- a/drivers/phy/ti/phy-dm816x-usb.c
+++ b/drivers/phy/ti/phy-dm816x-usb.c
@@ -12,10 +12,11 @@
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
-#include <linux/phy/phy.h>
#include <linux/mfd/syscon.h>
+#include "../phy-provider.h"
+
/*
* TRM has two sets of USB_CTRL registers.. The correct register bits
* are in TRM section 24.9.8.2 USB_CTRL Register. The TRM documents the
diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index 6213c2b6005a..ce7dc692d7be 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -14,9 +14,10 @@
#include <linux/of_address.h>
#include <linux/of_net.h>
#include <linux/phy.h>
-#include <linux/phy/phy.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
/* AM33xx SoC specific definitions for the CONTROL port */
#define AM33XX_GMII_SEL_MODE_MII 0
#define AM33XX_GMII_SEL_MODE_RMII 1
diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c
index 1eb252604441..318f51d09c28 100644
--- a/drivers/phy/ti/phy-omap-usb2.c
+++ b/drivers/phy/ti/phy-omap-usb2.c
@@ -16,7 +16,6 @@
#include <linux/of_platform.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/phy/omap_usb.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -25,6 +24,8 @@
#include <linux/sys_soc.h>
#include <linux/usb/phy_companion.h>
+#include "../phy-provider.h"
+
#define USB2PHY_ANA_CONFIG1 0x4c
#define USB2PHY_DISCON_BYP_LATCH BIT(31)
diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c
index b5543b5c674c..d63c8e872d5b 100644
--- a/drivers/phy/ti/phy-ti-pipe3.c
+++ b/drivers/phy/ti/phy-ti-pipe3.c
@@ -10,7 +10,6 @@
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
-#include <linux/phy/phy.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -22,6 +21,8 @@
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include "../phy-provider.h"
+
#define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008
#define PLL_CONFIGURATION1 0x0000000C
diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c
index a26aec3ab29e..67c9883691fc 100644
--- a/drivers/phy/ti/phy-twl4030-usb.c
+++ b/drivers/phy/ti/phy-twl4030-usb.c
@@ -20,7 +20,6 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/usb/otg.h>
-#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/usb/musb.h>
#include <linux/usb/ulpi.h>
@@ -29,6 +28,8 @@
#include <linux/err.h>
#include <linux/slab.h>
+#include "../phy-provider.h"
+
/* Register defines */
#define MCPC_CTRL 0x30
diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
index fe6b4925d166..db40594622da 100644
--- a/drivers/phy/xilinx/phy-zynqmp.c
+++ b/drivers/phy/xilinx/phy-zynqmp.c
@@ -12,6 +12,7 @@
* PCIe should also work but that is experimental as of now.
*/
+#include <dt-bindings/phy/phy.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -19,12 +20,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <dt-bindings/phy/phy.h>
+#include "../phy-provider.h"
/*
* Lane Registers
diff --git a/include/linux/phy/phy-sun4i-usb.h b/include/linux/phy/phy-sun4i-usb.h
index f3e7b13608e4..66612be0dac5 100644
--- a/include/linux/phy/phy-sun4i-usb.h
+++ b/include/linux/phy/phy-sun4i-usb.h
@@ -6,7 +6,7 @@
#ifndef PHY_SUN4I_USB_H_
#define PHY_SUN4I_USB_H_
-#include "phy.h"
+struct phy;
/**
* sun4i_usb_phy_set_squelch_detect() - Enable/disable squelch detect
diff --git a/include/linux/phy/tegra/xusb.h b/include/linux/phy/tegra/xusb.h
index 6ca51e0080ec..e6c613f9bef2 100644
--- a/include/linux/phy/tegra/xusb.h
+++ b/include/linux/phy/tegra/xusb.h
@@ -8,6 +8,7 @@
struct tegra_xusb_padctl;
struct device;
+struct phy;
enum usb_device_speed;
struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev);
diff --git a/include/linux/phy/ulpi_phy.h b/include/linux/phy/ulpi_phy.h
index 7054b440347c..0f9e8430d398 100644
--- a/include/linux/phy/ulpi_phy.h
+++ b/include/linux/phy/ulpi_phy.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/phy/phy.h>
+#include "../../drivers/phy/phy-provider.h"
/**
* Helper that registers PHY for a ULPI device and adds a lookup for binding it
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH v6 phy-next 09/28] scsi: ufs: exynos: stop poking into struct phy guts
From: Martin K. Petersen @ 2026-03-27 20:19 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, 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, Bart Van Assche, Alim Akhtar, Peter Griffin,
James E.J. Bottomley, Martin K. Petersen, Krzysztof Kozlowski,
Chanho Park
In-Reply-To: <20260327184706.1600329-10-vladimir.oltean@nxp.com>
Vladimir,
> The Exynos host controller driver is clearly a PHY consumer (gets the
> ufs->phy using devm_phy_get()), but pokes into the guts of struct phy
> to get the generic_phy->power_count.
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
--
Martin K. Petersen
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v6 phy-next 11/28] scsi: ufs: qcom: include missing <linux/interrupt.h>
From: Martin K. Petersen @ 2026-03-27 20:20 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, 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, Manivannan Sadhasivam, James E.J. Bottomley,
Martin K. Petersen
In-Reply-To: <20260327184706.1600329-12-vladimir.oltean@nxp.com>
Vladimir,
> The point is that <linux/phy/phy.h> will stop providing
> <linux/regulator/consumer.h>, and this would break the transitive
> include chain on armv7.
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
--
Martin K. Petersen
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v6 phy-next 09/28] scsi: ufs: exynos: stop poking into struct phy guts
From: Peter Griffin @ 2026-03-27 20:23 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, 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, Bart Van Assche, Alim Akhtar,
James E.J. Bottomley, Martin K. Petersen, Krzysztof Kozlowski,
Chanho Park
In-Reply-To: <20260327184706.1600329-10-vladimir.oltean@nxp.com>
On Fri, 27 Mar 2026 at 18:48, Vladimir Oltean <vladimir.oltean@nxp.com> wrote:
>
> The Exynos host controller driver is clearly a PHY consumer (gets the
> ufs->phy using devm_phy_get()), but pokes into the guts of struct phy
> to get the generic_phy->power_count.
>
> The UFS core (specifically ufshcd_link_startup()) may call the variant
> operation exynos_ufs_pre_link() -> exynos_ufs_phy_init() multiple times
> if the link startup fails and needs to be retried.
>
> However ufs-exynos shouldn't be doing what it's doing, i.e. looking at
> the generic_phy->power_count, because in the general sense of the API, a
> single Generic PHY may have multiple consumers. If ufs-exynos looks at
> generic_phy->power_count, there's no guarantee that this ufs-exynos
> instance is the one who previously bumped that power count. So it may be
> powering down the PHY on behalf of another consumer.
>
> The correct way in which this should be handled is ufs-exynos should
> *remember* whether it has initialized and powered up the PHY before, and
> power it down during link retries. Not rely on the power_count (which,
> btw, on the writer side is modified under &phy->mutex, but on the reader
> side is accessed unlocked). This is a discouraged pattern even if here
> it doesn't cause functional problems.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
> Acked-by: Alim Akhtar <alim.akhtar@samsung.com>
> Tested-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
Reviewed-by: Peter Griffin <peter.griffin@linaro.org>
> Cc: Alim Akhtar <alim.akhtar@samsung.com>
> Cc: Peter Griffin <peter.griffin@linaro.org>
> Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
> Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
> Cc: Krzysztof Kozlowski <krzk@kernel.org>
> Cc: Chanho Park <chanho61.park@samsung.com>
>
> v5->v6: collect tags from Alim Akhtar
> v4->v5: collect tag, add "scsi: " prefix to commit title
> v3->v4: none
> v2->v3:
> - add Cc Chanho Park, author of commit 3d73b200f989 ("scsi: ufs:
> ufs-exynos: Change ufs phy control sequence")
> v1->v2:
> - add better ufs->phy_powered_on handling in exynos_ufs_exit(),
> exynos_ufs_suspend() and exynos_ufs_resume() which ensures we won't
> enter a phy->power_count underrun condition
> ---
> drivers/ufs/host/ufs-exynos.c | 24 ++++++++++++++++++++----
> drivers/ufs/host/ufs-exynos.h | 1 +
> 2 files changed, 21 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c
> index 76fee3a79c77..274e53833571 100644
> --- a/drivers/ufs/host/ufs-exynos.c
> +++ b/drivers/ufs/host/ufs-exynos.c
> @@ -963,9 +963,10 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)
>
> phy_set_bus_width(generic_phy, ufs->avail_ln_rx);
>
> - if (generic_phy->power_count) {
> + if (ufs->phy_powered_on) {
> phy_power_off(generic_phy);
> phy_exit(generic_phy);
> + ufs->phy_powered_on = false;
> }
>
> ret = phy_init(generic_phy);
> @@ -979,6 +980,8 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)
> if (ret)
> goto out_exit_phy;
>
> + ufs->phy_powered_on = true;
> +
> return 0;
>
> out_exit_phy:
> @@ -1527,6 +1530,9 @@ static void exynos_ufs_exit(struct ufs_hba *hba)
> {
> struct exynos_ufs *ufs = ufshcd_get_variant(hba);
>
> + if (!ufs->phy_powered_on)
> + return;
> +
> phy_power_off(ufs->phy);
> phy_exit(ufs->phy);
> }
> @@ -1728,8 +1734,10 @@ static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
> if (ufs->drv_data->suspend)
> ufs->drv_data->suspend(ufs);
>
> - if (!ufshcd_is_link_active(hba))
> + if (!ufshcd_is_link_active(hba) && ufs->phy_powered_on) {
> phy_power_off(ufs->phy);
> + ufs->phy_powered_on = false;
> + }
>
> return 0;
> }
> @@ -1737,9 +1745,17 @@ static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
> static int exynos_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
> {
> struct exynos_ufs *ufs = ufshcd_get_variant(hba);
> + int err;
>
> - if (!ufshcd_is_link_active(hba))
> - phy_power_on(ufs->phy);
> + if (!ufshcd_is_link_active(hba) && !ufs->phy_powered_on) {
> + err = phy_power_on(ufs->phy);
> + if (err) {
> + dev_err(hba->dev, "Failed to power on PHY: %pe\n",
> + ERR_PTR(err));
> + } else {
> + ufs->phy_powered_on = true;
> + }
> + }
>
> exynos_ufs_config_smu(ufs);
> exynos_ufs_fmp_resume(hba);
> diff --git a/drivers/ufs/host/ufs-exynos.h b/drivers/ufs/host/ufs-exynos.h
> index abe7e472759e..683b9150e2ba 100644
> --- a/drivers/ufs/host/ufs-exynos.h
> +++ b/drivers/ufs/host/ufs-exynos.h
> @@ -227,6 +227,7 @@ struct exynos_ufs {
> int avail_ln_rx;
> int avail_ln_tx;
> int rx_sel_idx;
> + bool phy_powered_on;
> struct ufs_pa_layer_attr dev_req_params;
> struct ufs_phy_time_cfg t_cfg;
> ktime_t entry_hibern8_t;
> --
> 2.43.0
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Dmitry Baryshkov @ 2026-03-27 20:51 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: Vladimir Zapolskiy, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, linux-arm-msm, linux-phy,
linux-media, devicetree, linux-kernel
In-Reply-To: <5d7d5bf8-4420-4d75-b928-820bb9233e52@kernel.org>
On Thu, Mar 26, 2026 at 02:42:10PM +0000, Bryan O'Donoghue wrote:
> On 26/03/2026 10:28, Vladimir Zapolskiy wrote:
> > On 3/26/26 04:03, Bryan O'Donoghue wrote:
> > > On 26/03/2026 01:46, Vladimir Zapolskiy wrote:
> > > > On 3/26/26 03:04, Bryan O'Donoghue wrote:
> > > > > Add a base schema initially compatible with x1e80100 to describe MIPI
> > > > > CSI2
> > > > > PHY devices.
> > > > >
> > > > > The hardware can support both CPHY, DPHY and a special split-mode
> > > > > DPHY. We
> > > > > capture those modes as:
> > > > >
> > > > > - PHY_QCOM_CSI2_MODE_DPHY
> > > > > - PHY_QCOM_CSI2_MODE_CPHY
> > > > > - PHY_QCOM_CSI2_MODE_SPLIT_DPHY
> > > >
> > > > Distinction between PHY_QCOM_CSI2_MODE_DPHY and
> > > > PHY_QCOM_CSI2_MODE_SPLIT_DPHY
> > > > is
> > > > 1) insufficient in just this simplistic form, because the assignment of
> > > > particular lanes is also needed,
> > > > 2) and under the assumption that the lane mapping is set somewhere else,
> > > > then
> > > > there should be no difference between PHY_QCOM_CSI2_MODE_{DPHY,SPLIT_DPHY},
> > > > it's just DPHY, and the subtype is deductible from data-lanes property on
> > > > the consumer side.
> > > >
> > > > So far the rationale is unclear, why anything above regular PHY_TYPE_DPHY
> > > > and PHY_TYPE_CPHY is needed here, those two are sufficient.
> > >
> > > Because knowing the split-mode exists and that you have asked about how
> > > such a thing would be supported, I thought about how to represent that
> > > mode right from the start, even if we don't support it.
> >
> > It is good to think about this hardware confguration in advance, however
> > the process of describing such hardware setup is incomplete.
> >
> > >
> > > To support split phy we will need to pass the parameter.
> >
> > What you call "split phy" is a DPHY, and "split phy" can not be supported
> > by adding this parameter, because it does not provide information about
> > lanes, and after removing this information it is just DPHY.
>
> That's just not true. If you read the camx source code you can see
> split/combo mode 2+1 1+1 data/clock mode requires special programming of the
> PHY to support.
This needs to be identified from the data-lanes / clock-lanes topology.
And once you do that, there would be (probably) no difference in the
hardware definition.
In other words, I'd also ask to drop this mode from the DT. This
infromation can and should be deduced from other, already-defined
properties.
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Dmitry Baryshkov @ 2026-03-27 20:54 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Bryan O'Donoghue, Vladimir Zapolskiy, linux-arm-msm,
linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <20260326-x1e-csi2-phy-v5-2-0c0fc7f5c01b@linaro.org>
On Thu, Mar 26, 2026 at 01:04:44AM +0000, Bryan O'Donoghue wrote:
> Add a new MIPI CSI2 driver in DPHY mode initially. The entire set of
> existing CAMSS CSI PHY init sequences are imported in order to save time
> and effort in later patches.
>
> The following devices are supported in this drop:
> "qcom,x1e80100-csi2-phy"
>
> In-line with other PHY drivers the process node is included in the name.
> Data-lane and clock lane positioning and polarity selection via newly
> amended struct phy_configure_opts_mipi_dphy{} is supported.
>
> The Qualcomm 3PH class of PHYs can do both DPHY and CPHY mode. For now only
> DPHY is supported.
>
> In porting some of the logic over from camss-csiphy*.c to here its also
> possible to rationalise some of the code.
>
> In particular use of regulator_bulk and clk_bulk as well as dropping the
> seemingly useless and unused interrupt handler.
>
> The PHY sequences and a lot of the logic that goes with them are well
> proven in CAMSS and mature so the main thing to watch out for here is how
> to get the right sequencing of regulators, clocks and register-writes.
>
> The register init sequence table is imported verbatim from the existing
> CAMSS csiphy driver. A follow-up series will rework the table to extract
> the repetitive per-lane pattern into a loop.
>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> ---
> MAINTAINERS | 11 +
> drivers/phy/qualcomm/Kconfig | 13 +
> drivers/phy/qualcomm/Makefile | 5 +
> drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 361 +++++++++++++++++++++
> drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c | 298 +++++++++++++++++
> drivers/phy/qualcomm/phy-qcom-mipi-csi2.h | 95 ++++++
> 6 files changed, 783 insertions(+)
>
> +/* 4nm 2PH v 2.1.2 2p5Gbps 4 lane DPHY mode */
> +static const struct
> +mipi_csi2phy_lane_regs lane_regs_x1e80100[] = {
> + /* Power up lanes 2ph mode */
> + {.reg_addr = 0x1014, .reg_data = 0xd5, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x101c, .reg_data = 0x7a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x1018, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> +
> + {.reg_addr = 0x0094, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x00a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0090, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0098, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0094, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0030, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0000, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0038, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x002c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0034, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x001c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0014, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x003c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0004, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0020, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0008, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0010, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0094, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x005c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0060, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0064, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
I think, I've left similar feedback already. Please rework a single
structure-less table into generic and per-lane configuration. It doesn't
make sense to repeat the same configuration N times, just with the
different offset.
> +
> + {.reg_addr = 0x0e94, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0ea0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e90, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e98, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e94, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e30, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e28, .reg_data = 0x04, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e00, .reg_data = 0x80, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e0c, .reg_data = 0xff, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e38, .reg_data = 0x1f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e2c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e34, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e1c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e14, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e3c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e04, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e20, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0e08, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0e10, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> +
> + {.reg_addr = 0x0494, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x04a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0490, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0498, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0494, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0430, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0400, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0438, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x042c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0434, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x041c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0414, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x043c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0404, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0420, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0408, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0410, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0494, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x045c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0460, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0464, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +
> + {.reg_addr = 0x0894, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x08a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0890, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0898, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0894, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0830, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0800, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0838, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x082c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0834, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x081c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0814, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x083c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0804, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0820, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0808, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0810, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0894, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x085c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0860, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0864, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +
> + {.reg_addr = 0x0c94, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0ca0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c90, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c98, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c94, .reg_data = 0x07, .delay_us = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c30, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c00, .reg_data = 0x8e, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c38, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c2c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c34, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c1c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c14, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c3c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c04, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c20, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c08, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE},
> + {.reg_addr = 0x0c10, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS},
> + {.reg_addr = 0x0c94, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0c5c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0c60, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL},
> + {.reg_addr = 0x0c64, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
> +};
> +
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Dmitry Baryshkov @ 2026-03-27 20:57 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Hangxiang Ma, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Bryan O'Donoghue,
Vladimir Zapolskiy, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <27adcbd2-0ec3-4a8f-84d6-ba381a66772d@oss.qualcomm.com>
On Fri, Mar 27, 2026 at 11:07:53AM +0100, Konrad Dybcio wrote:
> On 3/27/26 3:23 AM, Hangxiang Ma wrote:
> > On 3/26/2026 9:04 AM, Bryan O'Donoghue wrote:
> >> +#include <linux/delay.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/time64.h>
> >> +
> >> +#include "phy-qcom-mipi-csi2.h"
> >> +
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(offset, n) ((offset) + 0x4 * (n))
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL0_PHY_SW_RESET BIT(0)
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE BIT(7)
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B BIT(0)
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID BIT(1)
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL10_IRQ_CLEAR_CMD BIT(0)
> >> +#define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(offset, n) ((offset) + 0xb0 + 0x4 * (n))
> >>
> > Hi Bryan, one minor observation on the following macro:
> >
> > CSIPHY_3PH_CMN_CSI_COMMON_STATUSn
> >
> > The 0xb0 offset implicitly assumes a fixed distance between the
> > common_ctrl and common_status register blocks. This holds for the PHYs
> > covered by this series, but on some other platforms (e.g. Kaanapali,
> > Pakala) the offset differs.
> >
> > That said, I think keeping this fixed value is reasonable for the scope
> > of the current PHY series, and it does help keep the macro set simple.
> > It might just be worth documenting this assumption (e.g. via a comment
> > or in the commit message).
> >
> > Alternatively, if future PHY variants need to support different layouts,
> > this could be made more extensible by moving the status base offset into
> > the per-PHY data (similar to other register layout parameters). But I
> > don’t think that needs to block the current series.
>
> If the register contents are generally similar but the bit positions
> and/or reg offsets differ, regmap_fields may be useful
Or platform-specific set of macros / reg accessors (as it was done in
QMP).
>
> Konrad
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Bryan O'Donoghue @ 2026-03-27 22:11 UTC (permalink / raw)
To: Dmitry Baryshkov, Bryan O'Donoghue
Cc: Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Vladimir Zapolskiy, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <62zcubxembr6iat4d7n3o7aecqtx3ne2a42ilxfoap65oaefhh@mecahghgrwrf>
On 27/03/2026 20:54, Dmitry Baryshkov wrote:
> I think, I've left similar feedback already. Please rework a single
> structure-less table into generic and per-lane configuration. It doesn't
> make sense to repeat the same configuration N times, just with the
> different offset.
If you remember you also said that was fine for a follow-on series after
merging, and you asked for a commit log to that effect.
i.e.
"The register init sequence table is imported verbatim from the existing
CAMSS csiphy driver. A follow-up series will rework the table to extract
the repetitive per-lane pattern into a loop."
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Bryan O'Donoghue @ 2026-03-27 22:29 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Vladimir Zapolskiy, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, linux-arm-msm, linux-phy,
linux-media, devicetree, linux-kernel
In-Reply-To: <2houacfdkozzk35ky5xtwe3utkvyx4lroyrhvibb5lg6lad2g6@56akvtqigaep>
On 27/03/2026 20:51, Dmitry Baryshkov wrote:
>> That's just not true. If you read the camx source code you can see
>> split/combo mode 2+1 1+1 data/clock mode requires special programming of the
>> PHY to support.
> This needs to be identified from the data-lanes / clock-lanes topology.
> And once you do that, there would be (probably) no difference in the
> hardware definition.
>
>
> In other words, I'd also ask to drop this mode from the DT. This
> infromation can and should be deduced from other, already-defined
> properties.
It still needs to be communicated to the PHY from the controller,
however that is not a problem I am trying to solve now.
If I can't get consensus for PHY_QCOM_CSI2_MODE_SPLIT_DPHY then so be it.
I'll aim for DPHY only and we can come back to this topic when someone
actually tries to enable it.
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Dmitry Baryshkov @ 2026-03-27 22:30 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: Bryan O'Donoghue, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Vladimir Zapolskiy, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <6c52f934-1b08-4e93-a753-d4c90e827f1f@kernel.org>
On Sat, 28 Mar 2026 at 00:11, Bryan O'Donoghue <bod@kernel.org> wrote:
>
> On 27/03/2026 20:54, Dmitry Baryshkov wrote:
> > I think, I've left similar feedback already. Please rework a single
> > structure-less table into generic and per-lane configuration. It doesn't
> > make sense to repeat the same configuration N times, just with the
> > different offset.
>
> If you remember you also said that was fine for a follow-on series after
> merging, and you asked for a commit log to that effect.
>
> i.e.
>
> "The register init sequence table is imported verbatim from the existing
> CAMSS csiphy driver. A follow-up series will rework the table to extract
> the repetitive per-lane pattern into a loop."
Ack.
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Vladimir Zapolskiy @ 2026-03-27 23:12 UTC (permalink / raw)
To: Bryan O'Donoghue, Dmitry Baryshkov
Cc: Bryan O'Donoghue, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
linux-arm-msm, linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <556a6736-472d-4551-b5df-15e809e7e20e@kernel.org>
On 3/28/26 00:29, Bryan O'Donoghue wrote:
> On 27/03/2026 20:51, Dmitry Baryshkov wrote:
>>> That's just not true. If you read the camx source code you can see
>>> split/combo mode 2+1 1+1 data/clock mode requires special programming of the
>>> PHY to support.
>> This needs to be identified from the data-lanes / clock-lanes topology.
>> And once you do that, there would be (probably) no difference in the
>> hardware definition.
>>
>>
>> In other words, I'd also ask to drop this mode from the DT. This
>> infromation can and should be deduced from other, already-defined
>> properties.
>
> It still needs to be communicated to the PHY from the controller,
> however that is not a problem I am trying to solve now.
>
> If I can't get consensus for PHY_QCOM_CSI2_MODE_SPLIT_DPHY then so be it.
>
> I'll aim for DPHY only and we can come back to this topic when someone
> actually tries to enable it.
>
DPHY may be the only supported phy type in the driver, it does not matter
at this point, however it's totally essential to cover the called by you
'split mode' right from the beginning in the renewed device tree binding
descriptions of CAMSS IPs to progress further.
--
Best wishes,
Vladimir
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Dmitry Baryshkov @ 2026-03-27 23:23 UTC (permalink / raw)
To: Vladimir Zapolskiy
Cc: Bryan O'Donoghue, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, linux-arm-msm, linux-phy,
linux-media, devicetree, linux-kernel
In-Reply-To: <a44a0f58-11cd-4aa4-962f-a5b153e24d82@linaro.org>
On Sat, Mar 28, 2026 at 01:12:22AM +0200, Vladimir Zapolskiy wrote:
> On 3/28/26 00:29, Bryan O'Donoghue wrote:
> > On 27/03/2026 20:51, Dmitry Baryshkov wrote:
> > > > That's just not true. If you read the camx source code you can see
> > > > split/combo mode 2+1 1+1 data/clock mode requires special programming of the
> > > > PHY to support.
> > > This needs to be identified from the data-lanes / clock-lanes topology.
> > > And once you do that, there would be (probably) no difference in the
> > > hardware definition.
> > >
> > >
> > > In other words, I'd also ask to drop this mode from the DT. This
> > > infromation can and should be deduced from other, already-defined
> > > properties.
> >
> > It still needs to be communicated to the PHY from the controller,
> > however that is not a problem I am trying to solve now.
> >
> > If I can't get consensus for PHY_QCOM_CSI2_MODE_SPLIT_DPHY then so be it.
> >
> > I'll aim for DPHY only and we can come back to this topic when someone
> > actually tries to enable it.
> >
>
> DPHY may be the only supported phy type in the driver, it does not matter
> at this point, however it's totally essential to cover the called by you
> 'split mode' right from the beginning in the renewed device tree binding
> descriptions of CAMSS IPs to progress further.
Okay. How would we describe that there are two sensors connected to the
single PHY anyway? How would it be described with the current bindings?
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Bryan O'Donoghue @ 2026-03-27 23:40 UTC (permalink / raw)
To: Dmitry Baryshkov, Vladimir Zapolskiy
Cc: Bryan O'Donoghue, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
linux-arm-msm, linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <qr6ubhjlzxenx7rswwkfu2nkc7ci5hw5tynpipa76bqsibbd3d@rw5d55vjnkbe>
On 27/03/2026 23:23, Dmitry Baryshkov wrote:
> On Sat, Mar 28, 2026 at 01:12:22AM +0200, Vladimir Zapolskiy wrote:
>> On 3/28/26 00:29, Bryan O'Donoghue wrote:
>>> On 27/03/2026 20:51, Dmitry Baryshkov wrote:
>>>>> That's just not true. If you read the camx source code you can see
>>>>> split/combo mode 2+1 1+1 data/clock mode requires special programming of the
>>>>> PHY to support.
>>>> This needs to be identified from the data-lanes / clock-lanes topology.
>>>> And once you do that, there would be (probably) no difference in the
>>>> hardware definition.
>>>>
>>>>
>>>> In other words, I'd also ask to drop this mode from the DT. This
>>>> infromation can and should be deduced from other, already-defined
>>>> properties.
>>>
>>> It still needs to be communicated to the PHY from the controller,
>>> however that is not a problem I am trying to solve now.
>>>
>>> If I can't get consensus for PHY_QCOM_CSI2_MODE_SPLIT_DPHY then so be it.
>>>
>>> I'll aim for DPHY only and we can come back to this topic when someone
>>> actually tries to enable it.
>>>
>>
>> DPHY may be the only supported phy type in the driver, it does not matter
>> at this point, however it's totally essential to cover the called by you
>> 'split mode' right from the beginning in the renewed device tree binding
>> descriptions of CAMSS IPs to progress further.
>
> Okay. How would we describe that there are two sensors connected to the
> single PHY anyway? How would it be described with the current bindings?
>
> --
> With best wishes
> Dmitry
Assuming you add endpoints to the PHY i.e. that is what Neil appears to
be asking for and I personally am _fine_ with that, then it should just be
port@0
port@1
if port@1 exists, you know you are in split-phy mode.
Its actually straight forward enough, really. To be clear though I can
write that yaml - the _most_ support I'm willing to put into the PHY
code is to detect the port@1 and say "nope not supported yet", since
like CPHY its not.
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Vladimir Zapolskiy @ 2026-03-28 0:41 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Bryan O'Donoghue, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, linux-arm-msm, linux-phy,
linux-media, devicetree, linux-kernel
In-Reply-To: <qr6ubhjlzxenx7rswwkfu2nkc7ci5hw5tynpipa76bqsibbd3d@rw5d55vjnkbe>
On 3/28/26 01:23, Dmitry Baryshkov wrote:
> On Sat, Mar 28, 2026 at 01:12:22AM +0200, Vladimir Zapolskiy wrote:
>> On 3/28/26 00:29, Bryan O'Donoghue wrote:
>>> On 27/03/2026 20:51, Dmitry Baryshkov wrote:
>>>>> That's just not true. If you read the camx source code you can see
>>>>> split/combo mode 2+1 1+1 data/clock mode requires special programming of the
>>>>> PHY to support.
>>>> This needs to be identified from the data-lanes / clock-lanes topology.
>>>> And once you do that, there would be (probably) no difference in the
>>>> hardware definition.
>>>>
>>>>
>>>> In other words, I'd also ask to drop this mode from the DT. This
>>>> infromation can and should be deduced from other, already-defined
>>>> properties.
>>>
>>> It still needs to be communicated to the PHY from the controller,
>>> however that is not a problem I am trying to solve now.
>>>
>>> If I can't get consensus for PHY_QCOM_CSI2_MODE_SPLIT_DPHY then so be it.
>>>
>>> I'll aim for DPHY only and we can come back to this topic when someone
>>> actually tries to enable it.
>>>
>>
>> DPHY may be the only supported phy type in the driver, it does not matter
>> at this point, however it's totally essential to cover the called by you
>> 'split mode' right from the beginning in the renewed device tree binding
>> descriptions of CAMSS IPs to progress further.
>
> Okay. How would we describe that there are two sensors connected to the
> single PHY anyway? How would it be described with the current bindings?
>
An RFC example was sent about one year ago, it allows to specify one or
two endpoints under a single phy port:
https://lore.kernel.org/linux-arm-msm/20250513143918.2572689-1-vladimir.zapolskiy@linaro.org/
--
Best wishes,
Vladimir
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 0/2] phy: hdmi: Add FRL TxFFE level control
From: Cristian Ciocaltea @ 2026-03-28 13:54 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner
Cc: kernel, linux-phy, linux-kernel, linux-arm-kernel, linux-rockchip
During HDMI 2.1 Fixed Rate Link training, the source and sink may
negotiate a Transmitter Feed Forward Equalizer (TxFFE) level to
compensate for signal quality degradation on the physical channel. The
source starts at level 0 and may increment it up to a maximum agreed
upon during LTS3 in response to persistent link failures reported by the
sink. TxFFE adjustment is optional and entirely independent of the FRL
rate and lane count selection.
Patch 1 extends the HDMI PHY configuration API with two new fields in
the frl sub-struct: ffe_level to carry the requested level, and a
set_ffe_level flag that switches the semantics of a phy_configure() call
to a pure equalizer update, leaving all other fields ignored.
Patch 2 implements the new interface in the Rockchip Samsung HDPTX PHY
driver.
The series depends on the "[PATCH 0/6] phy: rockchip: samsung-hdptx:
Clock fixes and API transition cleanups" patchset:
https://lore.kernel.org/all/20260227-hdptx-clk-fixes-v1-0-f998f2762d0f@collabora.com/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
Cristian Ciocaltea (2):
phy: hdmi: Add optional FRL TxFFE config options
phy: rockchip: samsung-hdptx: Add support for FRL TxFFE level control
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 74 +++++++++++++++++++++--
include/linux/phy/phy-hdmi.h | 6 ++
2 files changed, 75 insertions(+), 5 deletions(-)
---
base-commit: f7b64ed948718290209074a50bb0df17e5944873
change-id: 20260328-hdptx-ffe-a89c51e66904
prerequisite-change-id: 20260227-hdptx-clk-fixes-47426632f862:v1
prerequisite-patch-id: 5c1d442fae39103bb758f54738aff33d2491401d
prerequisite-patch-id: b86f30292308345387d2a6b50949ad040b931592
prerequisite-patch-id: b1335105db9177cb10c64ed1bf0867832e6aac2f
prerequisite-patch-id: 83db6603d13e19f239e89fde2b26366eb0106b7e
prerequisite-patch-id: b534395ad315811861f11859a3946f65c90c631a
prerequisite-patch-id: f9637e57c902f35218cda658397416f84f7285cb
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 1/2] phy: hdmi: Add optional FRL TxFFE config options
From: Cristian Ciocaltea @ 2026-03-28 13:54 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner
Cc: kernel, linux-phy, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260328-hdptx-ffe-v1-0-53ebd5dea20a@collabora.com>
During HDMI 2.1 FRL link training, the source and sink can negotiate a
Transmitter Feed Forward Equalizer (TxFFE) level to compensate for
signal quality degradation. Starting from zero, the source may
increment the TxFFE level up to a maximum agreed during the LTS3 stage
if the sink keeps reporting FLT failures.
It's worth noting TxFFE adjustment is optional and only attempted when
both the source and the connected sink support it.
Since the existing HDMI PHY configuration API covers the FRL rate/lane
selection only, provide the following fields to the frl sub-struct of
phy_configure_opts_hdmi:
* ffe_level: the TxFFE level to apply, only meaningful when
set_ffe_level is set.
* set_ffe_level: a 1-bit flag that changes the semantics of the
phy_configure() call, i.e. when set, the PHY driver must apply the new
ffe_level and ignore the other frl related fields.
The flag-based approach reflects an important invariant in the link
training process: whenever the FRL rate or lane count changes, the TxFFE
level must be reset to zero. A separate phy_configure() call with
set_ffe_level can only follow after the rate has been established,
making the two operations deliberately distinct.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
include/linux/phy/phy-hdmi.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/linux/phy/phy-hdmi.h b/include/linux/phy/phy-hdmi.h
index d4cf4430ee8f..1d4b62475079 100644
--- a/include/linux/phy/phy-hdmi.h
+++ b/include/linux/phy/phy-hdmi.h
@@ -19,6 +19,10 @@ enum phy_hdmi_mode {
* @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
* @frl.rate_per_lane: HDMI FRL Rate per Lane in Gbps.
* @frl.lanes: HDMI FRL lanes count.
+ * @frl.ffe_level: Transmitter Feed Forward Equalizer Level.
+ * Optional, only meaningful when set_ffe_level flag is on.
+ * @frl.set_ffe_level: Flag indicating whether or not to reconfigure ffe_level.
+ * All the other struct fields must be ignored when this is used.
*
* This structure is used to represent the configuration state of a HDMI phy.
*/
@@ -29,6 +33,8 @@ struct phy_configure_opts_hdmi {
struct {
u8 rate_per_lane;
u8 lanes;
+ u8 ffe_level;
+ u8 set_ffe_level : 1;
} frl;
};
};
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 2/2] phy: rockchip: samsung-hdptx: Add support for FRL TxFFE level control
From: Cristian Ciocaltea @ 2026-03-28 13:54 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Heiko Stuebner
Cc: kernel, linux-phy, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260328-hdptx-ffe-v1-0-53ebd5dea20a@collabora.com>
During HDMI 2.1 FRL link training, the source may need to incrementally
raise the TxFFE level in response to persistent link failures reported
by the sink during LTS3. The phy_configure_opts_hdmi struct now carries
ffe_level and set_ffe_level fields to convey such an update
independently of a full rate reconfiguration.
Wire up the optional TxFFE control in the Samsung HDPTX PHY driver.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 74 +++++++++++++++++++++--
1 file changed, 69 insertions(+), 5 deletions(-)
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 3bde7fbb34b1..c4669853ad0e 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -333,6 +333,7 @@
#define FRL_3G3L_RATE 900000000
#define FRL_6G3L_RATE 1800000000
#define FRL_8G4L_RATE 3200000000
+#define FRL_FFE_MAX_LEVEL 3
enum dp_link_rate {
DP_BW_RBR,
@@ -466,6 +467,16 @@ static const struct ropll_config rk_hdptx_tmds_ropll_cfg[] = {
{ 25175000ULL, 84, 84, 1, 1, 15, 1, 168, 1, 16, 4, 1, 1, },
};
+static const struct ffe_config {
+ u8 pre_shoot;
+ u8 de_emphasis;
+} rk_hdptx_frl_ffe_cfg[FRL_FFE_MAX_LEVEL + 1] = {
+ { 0x3, 0x4 },
+ { 0x3, 0x6 },
+ { 0x3, 0x8 },
+ { 0x3, 0x9 },
+};
+
static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(0009), 0x0c),
REG_SEQ0(CMN_REG(000a), 0x83),
@@ -1321,6 +1332,45 @@ static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
return rk_hdptx_post_enable_lane(hdptx);
}
+static int rk_hdptx_frl_ffe_config(struct rk_hdptx_phy *hdptx, u8 ffe_level)
+{
+ u8 val;
+
+ if (ffe_level > FRL_FFE_MAX_LEVEL)
+ return -EINVAL;
+
+ val = rk_hdptx_frl_ffe_cfg[ffe_level].pre_shoot;
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(0305),
+ LN_TX_DRV_PRE_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_PRE_LVL_CTRL_MASK, val));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0405),
+ LN_TX_DRV_PRE_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_PRE_LVL_CTRL_MASK, val));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0505),
+ LN_TX_DRV_PRE_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_PRE_LVL_CTRL_MASK, val));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0605),
+ LN_TX_DRV_PRE_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_PRE_LVL_CTRL_MASK, val));
+
+ val = rk_hdptx_frl_ffe_cfg[ffe_level].de_emphasis;
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(0304),
+ LN_TX_DRV_POST_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_POST_LVL_CTRL_MASK, val));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0404),
+ LN_TX_DRV_POST_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_POST_LVL_CTRL_MASK, val));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0504),
+ LN_TX_DRV_POST_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_POST_LVL_CTRL_MASK, val));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0604),
+ LN_TX_DRV_POST_LVL_CTRL_MASK,
+ FIELD_PREP(LN_TX_DRV_POST_LVL_CTRL_MASK, val));
+ return 0;
+}
+
static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
{
reset_control_assert(hdptx->rsts[RST_LANE].rstc);
@@ -1730,6 +1780,13 @@ static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
unsigned long long frl_rate = 100000000ULL * hdmi_in->frl.lanes *
hdmi_in->frl.rate_per_lane;
+ if (hdmi_in->frl.set_ffe_level) {
+ if (hdmi_in->frl.ffe_level > FRL_FFE_MAX_LEVEL)
+ return -EINVAL;
+
+ return 0;
+ }
+
switch (hdmi_in->frl.rate_per_lane) {
case 3:
case 6:
@@ -2076,11 +2133,18 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
if (ret) {
dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
} else {
- hdptx->pll_config_dirty = true;
-
- dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__,
- hdptx->hdmi_cfg.mode ? "FRL" : "TMDS",
- hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
+ if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL &&
+ opts->hdmi.frl.set_ffe_level) {
+ dev_dbg(hdptx->dev, "%s ffe_level=%u\n", __func__,
+ opts->hdmi.frl.ffe_level);
+ ret = rk_hdptx_frl_ffe_config(hdptx, opts->hdmi.frl.ffe_level);
+ } else {
+ hdptx->pll_config_dirty = true;
+
+ dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__,
+ hdptx->hdmi_cfg.mode ? "FRL" : "TMDS",
+ hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
+ }
}
return ret;
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Dmitry Baryshkov @ 2026-03-29 10:54 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: Vladimir Zapolskiy, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, linux-arm-msm, linux-phy,
linux-media, devicetree, linux-kernel
In-Reply-To: <0322e0b3-bce8-4415-90b2-d14445986e23@kernel.org>
On Fri, Mar 27, 2026 at 11:40:51PM +0000, Bryan O'Donoghue wrote:
> On 27/03/2026 23:23, Dmitry Baryshkov wrote:
> > On Sat, Mar 28, 2026 at 01:12:22AM +0200, Vladimir Zapolskiy wrote:
> > > On 3/28/26 00:29, Bryan O'Donoghue wrote:
> > > > On 27/03/2026 20:51, Dmitry Baryshkov wrote:
> > > > > > That's just not true. If you read the camx source code you can see
> > > > > > split/combo mode 2+1 1+1 data/clock mode requires special programming of the
> > > > > > PHY to support.
> > > > > This needs to be identified from the data-lanes / clock-lanes topology.
> > > > > And once you do that, there would be (probably) no difference in the
> > > > > hardware definition.
> > > > >
> > > > >
> > > > > In other words, I'd also ask to drop this mode from the DT. This
> > > > > infromation can and should be deduced from other, already-defined
> > > > > properties.
> > > >
> > > > It still needs to be communicated to the PHY from the controller,
> > > > however that is not a problem I am trying to solve now.
> > > >
> > > > If I can't get consensus for PHY_QCOM_CSI2_MODE_SPLIT_DPHY then so be it.
> > > >
> > > > I'll aim for DPHY only and we can come back to this topic when someone
> > > > actually tries to enable it.
> > > >
> > >
> > > DPHY may be the only supported phy type in the driver, it does not matter
> > > at this point, however it's totally essential to cover the called by you
> > > 'split mode' right from the beginning in the renewed device tree binding
> > > descriptions of CAMSS IPs to progress further.
> >
> > Okay. How would we describe that there are two sensors connected to the
> > single PHY anyway? How would it be described with the current bindings?
> >
> > --
> > With best wishes
> > Dmitry
>
> Assuming you add endpoints to the PHY i.e. that is what Neil appears to be
> asking for and I personally am _fine_ with that, then it should just be
>
> port@0
> port@1
>
> if port@1 exists, you know you are in split-phy mode.
>
> Its actually straight forward enough, really. To be clear though I can write
> that yaml - the _most_ support I'm willing to put into the PHY code is to
> detect the port@1 and say "nope not supported yet", since like CPHY its not.
SGTM. But let's define the schema for those usecases.
>
> ---
> bod
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v6 phy-next 00/28] Split Generic PHY consumer and provider
From: Vladimir Oltean @ 2026-03-27 18:46 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, James E.J. Bottomley,
JC Kuo, Jernej Skrabec, Jessica Zhang, Joe Perches, Johan Hovold,
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, Martin K. Petersen,
Mathias Nyman, Mauro Carvalho Chehab, Maxime Ripard, Michael Dege,
Nicolas Ferre, Niklas Cassel, Nitin Rawat, 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 28/28 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
(25/28 and 26/28).
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, but recommended) Said tag is merged back into affected
subsystem 'next' branches. Those who strongly prefer can handle merge
conflicts when they send their PR. But this series unexports a lot of
stuff from <linux/phy/phy.h> which may cause breakage if still used
later, directly or not, in other subsystems.
Detailed change log in patches, summary below.
v5->v6:
- new patch 11/28 to avoid build breakage in ufs-qcom.c for armv7
- expanded CC list coverage
v4->v5:
- fix additional compilation breakage caught by better build coverage.
PCI patch 02/27 received an extra change for pcie-spacemit-k1.c,
patch 10/27 (for ufs-qcom.c) is new, so are 12/27 and 13/27 for Tegra
USB (host and gadget)
v3->v4:
- fix build breakage in drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c and
include/linux/phy/tegra/xusb.h added by patch 22/24
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-v6
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-v6-merge/
v5 at:
https://lore.kernel.org/linux-phy/20260319223241.1351137-1-vladimir.oltean@nxp.com/
v4 at:
https://lore.kernel.org/linux-phy/20260317230500.2056077-1-vladimir.oltean@nxp.com/
v3 at:
https://lore.kernel.org/linux-phy/20260309190842.927634-1-vladimir.oltean@nxp.com/
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: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: JC Kuo <jckuo@nvidia.com>
Cc: Jernej Skrabec <jernej.skrabec@gmail.com>
Cc: Jessica Zhang <jesszhan0024@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Johan Hovold <johan+linaro@kernel.org>
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: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Mathias Nyman <mathias.nyman@intel.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: Nitin Rawat <quic_nitirawa@quicinc.com>
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 (28):
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
scsi: ufs: exynos: stop poking into struct phy guts
scsi: ufs: qcom: keep parallel track of PHY power state
scsi: ufs: qcom: include missing <linux/interrupt.h>
drm/rockchip: dw_hdmi: avoid direct dereference of phy->dev.of_node
usb: host: tegra: avoid direct dereference of phy->dev.of_node
usb: gadget: tegra-xudc: 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 | 3 +
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/ufs/host/ufs-qcom.c | 16 +-
drivers/ufs/host/ufs-qcom.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 +
drivers/usb/gadget/udc/tegra-xudc.c | 35 +-
drivers/usb/host/xhci-tegra.c | 42 +-
include/linux/phy/phy-props.h | 75 +++
include/linux/phy/phy-sun4i-usb.h | 2 +-
include/linux/phy/phy.h | 497 ++++--------------
include/linux/phy/tegra/xusb.h | 1 +
include/linux/phy/ulpi_phy.h | 2 +-
242 files changed, 1003 insertions(+), 739 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 v6 phy-next 27/28] phy: remove temporary provider compatibility from consumer header
From: Vladimir Oltean @ 2026-03-27 18:47 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, Dmitry Baryshkov, 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,
James E.J. Bottomley, JC Kuo, Jernej Skrabec, Jessica Zhang,
Joe Perches, Johan Hovold, 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, Martin K. Petersen, Mathias Nyman,
Mauro Carvalho Chehab, Maxime Ripard, Michael Dege, Nicolas Ferre,
Niklas Cassel, Nitin Rawat, 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
In-Reply-To: <20260327184706.1600329-1-vladimir.oltean@nxp.com>
Now that all consumers have been updated to no longer dereference fields
inside struct phy, we can hide its definition altogether from public view.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.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: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: JC Kuo <jckuo@nvidia.com>
Cc: Jernej Skrabec <jernej.skrabec@gmail.com>
Cc: Jessica Zhang <jesszhan0024@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Johan Hovold <johan+linaro@kernel.org>
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: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Mathias Nyman <mathias.nyman@intel.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: Nitin Rawat <quic_nitirawa@quicinc.com>
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>
v5->v6:
- expand CC list to inform maintainers of touched drivers that the API
is becoming unavailable
v2->v5: none
v1->v2: collect tag
---
include/linux/phy/phy.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 34b656084caf..0fdcefaa3f55 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -12,8 +12,6 @@
#include <linux/phy/phy-props.h>
-#include "../../../drivers/phy/phy-provider.h"
-
struct device;
struct device_node;
struct phy;
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 phy-next 16/28] phy: move provider API out of public <linux/phy/phy.h>
From: Vladimir Oltean @ 2026-03-27 18:46 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, Dmitry Baryshkov, 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,
James E.J. Bottomley, JC Kuo, Jernej Skrabec, Jessica Zhang,
Joe Perches, Johan Hovold, 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, Martin K. Petersen, Mathias Nyman,
Mauro Carvalho Chehab, Maxime Ripard, Michael Dege, Nicolas Ferre,
Niklas Cassel, Nitin Rawat, 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
In-Reply-To: <20260327184706.1600329-1-vladimir.oltean@nxp.com>
The major goal is to hide the contents of struct phy from consumer
drivers.
The idea with "phy-props.h" is that both consumers and providers make
use of some data types. So both headers include "phy-props.h".
Some slight points of contention.
1. phy_set_bus_width(): Vinod explains that despite the current caller
situation (9 providers, 1 consumer), it is a consumer API function.
The use case is that the controller (for example UFS) may have
limitations and should set the expected lanes to be used and width on
those lanes. A number of Generic PHYs can support multiple lanes and
multiple width so this is way for controller telling I am using this
configuration.
2. phy-provider.h should go to include/linux/phy/ or to drivers/phy/?
We do have 3 PHY providers outside of drivers/phy/:
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
drivers/pinctrl/tegra/pinctrl-tegra-xusb.c
but the practice is not encouraged, and with time, these should be
moved to the subsystem. This is not something that I can do now.
3. We can no longer tolerate static inline helpers. Allowing these would
make it impossible to hide the struct phy definition from consumers.
I've made phy_get_mode(), phy_get_bus_width(), phy_set_bus_width()
exported symbols in drivers/phy/phy-core.c.
4. This is not a change without side effects. In the transition we are
no longer providing <linux/pm_runtime.h> at all, and
<linux/regulator/consumer.h> to PHY consumer drivers. However, the
in-tree dependencies should all have been resolved. Also, the
movement of phy-provider.h to drivers/phy/ is at least "interesting"
for out of tree PHY provider drivers (this header is not deployed by
make headers_install). However, it seems to be what Vinod is looking
to see.
For temporary compatibility, keep including the provider header. This
will be removed when abuses are all gotten rid of.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.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: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: JC Kuo <jckuo@nvidia.com>
Cc: Jernej Skrabec <jernej.skrabec@gmail.com>
Cc: Jessica Zhang <jesszhan0024@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Johan Hovold <johan+linaro@kernel.org>
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: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Mathias Nyman <mathias.nyman@intel.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: Nitin Rawat <quic_nitirawa@quicinc.com>
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>
v5->v6:
- expand CC list to inform maintainers of touched drivers that the API
is becoming unavailable
v2->v5: none
v1->v2:
- collect tag
- fix path to phy-provider.h
- update commit message with the 4th point of contention
---
drivers/phy/phy-core.c | 34 +++
drivers/phy/phy-provider.h | 256 +++++++++++++++++
include/linux/phy/phy-props.h | 75 +++++
include/linux/phy/phy.h | 497 +++++++---------------------------
4 files changed, 456 insertions(+), 406 deletions(-)
create mode 100644 drivers/phy/phy-provider.h
create mode 100644 include/linux/phy/phy-props.h
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 21aaf2f76e53..a1aff00fba7c 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -20,6 +20,22 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#define to_phy(a) (container_of((a), struct phy, dev))
+
+/**
+ * struct phy_lookup - PHY association in list of phys managed by the phy driver
+ * @node: list node
+ * @dev_id: the device of the association
+ * @con_id: connection ID string on device
+ * @phy: the phy of the association
+ */
+struct phy_lookup {
+ struct list_head node;
+ const char *dev_id;
+ const char *con_id;
+ struct phy *phy;
+};
+
static void phy_release(struct device *dev);
static const struct class phy_class = {
.name = "phy",
@@ -606,6 +622,24 @@ int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
}
EXPORT_SYMBOL_GPL(phy_validate);
+enum phy_mode phy_get_mode(struct phy *phy)
+{
+ return phy->attrs.mode;
+}
+EXPORT_SYMBOL_GPL(phy_get_mode);
+
+int phy_get_bus_width(struct phy *phy)
+{
+ return phy->attrs.bus_width;
+}
+EXPORT_SYMBOL_GPL(phy_get_bus_width);
+
+void phy_set_bus_width(struct phy *phy, int bus_width)
+{
+ phy->attrs.bus_width = bus_width;
+}
+EXPORT_SYMBOL_GPL(phy_set_bus_width);
+
/**
* _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/drivers/phy/phy-provider.h b/drivers/phy/phy-provider.h
new file mode 100644
index 000000000000..0637278a2d8d
--- /dev/null
+++ b/drivers/phy/phy-provider.h
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * phy-provider.h -- Generic PHY provider API
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+#ifndef __PHY_PROVIDER_H
+#define __PHY_PROVIDER_H
+
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/phy/phy-props.h>
+
+struct phy;
+
+/**
+ * struct phy_ops - set of function pointers for performing phy operations
+ * @init: operation to be performed for initializing phy
+ * @exit: operation to be performed while exiting
+ * @power_on: powering on the phy
+ * @power_off: powering off the phy
+ * @set_mode: set the mode of the phy
+ * @set_media: set the media type of the phy (optional)
+ * @set_speed: set the speed of the phy (optional)
+ * @reset: resetting the phy
+ * @calibrate: calibrate the phy
+ * @notify_phystate: notify and configure the phy for a particular state
+ * @release: ops to be performed while the consumer relinquishes the PHY
+ * @owner: the module owner containing the ops
+ */
+struct phy_ops {
+ int (*init)(struct phy *phy);
+ int (*exit)(struct phy *phy);
+ int (*power_on)(struct phy *phy);
+ int (*power_off)(struct phy *phy);
+ int (*set_mode)(struct phy *phy, enum phy_mode mode, int submode);
+ int (*set_media)(struct phy *phy, enum phy_media media);
+ int (*set_speed)(struct phy *phy, int speed);
+
+ /**
+ * @configure:
+ *
+ * Optional.
+ *
+ * Used to change the PHY parameters. phy_init() must have
+ * been called on the phy.
+ *
+ * Returns: 0 if successful, an negative error code otherwise
+ */
+ int (*configure)(struct phy *phy, union phy_configure_opts *opts);
+
+ /**
+ * @validate:
+ *
+ * Optional.
+ *
+ * Used to check that the current set of parameters can be
+ * handled by the phy. Implementations are free to tune the
+ * parameters passed as arguments if needed by some
+ * implementation detail or constraints. It must not change
+ * any actual configuration of the PHY, so calling it as many
+ * times as deemed fit by the consumer must have no side
+ * effect.
+ *
+ * Returns: 0 if the configuration can be applied, an negative
+ * error code otherwise
+ */
+ int (*validate)(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts);
+ int (*reset)(struct phy *phy);
+ int (*calibrate)(struct phy *phy);
+
+ /* notify phy connect status change */
+ int (*connect)(struct phy *phy, int port);
+ int (*disconnect)(struct phy *phy, int port);
+
+ int (*notify_phystate)(struct phy *phy, union phy_notify state);
+ void (*release)(struct phy *phy);
+ struct module *owner;
+};
+
+/**
+ * struct phy_attrs - represents phy attributes
+ * @bus_width: Data path width implemented by PHY
+ * @max_link_rate: Maximum link rate supported by PHY (units to be decided by producer and consumer)
+ * @mode: PHY mode
+ */
+struct phy_attrs {
+ u32 bus_width;
+ u32 max_link_rate;
+ enum phy_mode mode;
+};
+
+/**
+ * struct phy - represents the phy device
+ * @dev: phy device
+ * @id: id of the phy device
+ * @ops: function pointers for performing phy operations
+ * @mutex: mutex to protect phy_ops
+ * @lockdep_key: lockdep information for this mutex
+ * @init_count: used to protect when the PHY is used by multiple consumers
+ * @power_count: used to protect when the PHY is used by multiple consumers
+ * @attrs: used to specify PHY specific attributes
+ * @pwr: power regulator associated with the phy
+ * @debugfs: debugfs directory
+ */
+struct phy {
+ struct device dev;
+ int id;
+ const struct phy_ops *ops;
+ struct mutex mutex;
+ struct lock_class_key lockdep_key;
+ int init_count;
+ int power_count;
+ struct phy_attrs attrs;
+ struct regulator *pwr;
+ struct dentry *debugfs;
+};
+
+/**
+ * struct phy_provider - represents the phy provider
+ * @dev: phy provider device
+ * @children: can be used to override the default (dev->of_node) child node
+ * @owner: the module owner having of_xlate
+ * @list: to maintain a linked list of PHY providers
+ * @of_xlate: function pointer to obtain phy instance from phy pointer
+ */
+struct phy_provider {
+ struct device *dev;
+ struct device_node *children;
+ struct module *owner;
+ struct list_head list;
+ struct phy *(*of_xlate)(struct device *dev,
+ const struct of_phandle_args *args);
+};
+
+#define of_phy_provider_register(dev, xlate) \
+ __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
+
+#define devm_of_phy_provider_register(dev, xlate) \
+ __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
+
+#define of_phy_provider_register_full(dev, children, xlate) \
+ __of_phy_provider_register(dev, children, THIS_MODULE, xlate)
+
+#define devm_of_phy_provider_register_full(dev, children, xlate) \
+ __devm_of_phy_provider_register(dev, children, THIS_MODULE, xlate)
+
+static inline void phy_set_drvdata(struct phy *phy, void *data)
+{
+ dev_set_drvdata(&phy->dev, data);
+}
+
+static inline void *phy_get_drvdata(struct phy *phy)
+{
+ return dev_get_drvdata(&phy->dev);
+}
+
+#if IS_ENABLED(CONFIG_GENERIC_PHY)
+struct phy *phy_create(struct device *dev, struct device_node *node,
+ const struct phy_ops *ops);
+struct phy *devm_phy_create(struct device *dev, struct device_node *node,
+ const struct phy_ops *ops);
+void phy_destroy(struct phy *phy);
+void devm_phy_destroy(struct device *dev, struct phy *phy);
+
+struct phy_provider *
+__of_phy_provider_register(struct device *dev, struct device_node *children,
+ struct module *owner,
+ struct phy *(*of_xlate)(struct device *dev,
+ const struct of_phandle_args *args));
+struct phy_provider *
+__devm_of_phy_provider_register(struct device *dev, struct device_node *children,
+ struct module *owner,
+ struct phy *(*of_xlate)(struct device *dev,
+ const struct of_phandle_args *args));
+void of_phy_provider_unregister(struct phy_provider *phy_provider);
+void devm_of_phy_provider_unregister(struct device *dev,
+ struct phy_provider *phy_provider);
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+struct phy *of_phy_simple_xlate(struct device *dev,
+ const struct of_phandle_args *args);
+#else
+static inline struct phy *phy_create(struct device *dev,
+ struct device_node *node,
+ const struct phy_ops *ops)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct phy *devm_phy_create(struct device *dev,
+ struct device_node *node,
+ const struct phy_ops *ops)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline void phy_destroy(struct phy *phy)
+{
+}
+
+static inline void devm_phy_destroy(struct device *dev, struct phy *phy)
+{
+}
+
+static inline struct phy_provider *
+__of_phy_provider_register(struct device *dev, struct device_node *children,
+ struct module *owner,
+ struct phy *(*of_xlate)(struct device *dev,
+ const struct of_phandle_args *args))
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct phy_provider *
+__devm_of_phy_provider_register(struct device *dev, struct device_node *children,
+ struct module *owner,
+ struct phy *(*of_xlate)(struct device *dev,
+ const struct of_phandle_args *args))
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline void of_phy_provider_unregister(struct phy_provider *phy_provider)
+{
+}
+
+static inline void devm_of_phy_provider_unregister(struct device *dev,
+ struct phy_provider *phy_provider)
+{
+}
+
+static inline int phy_create_lookup(struct phy *phy, const char *con_id,
+ const char *dev_id)
+{
+ return 0;
+}
+
+static inline void phy_remove_lookup(struct phy *phy, const char *con_id,
+ const char *dev_id)
+{
+}
+
+static inline struct phy *of_phy_simple_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif /* IS_ENABLED(CONFIG_GENERIC_PHY) */
+
+#endif /* __PHY_PROVIDER_H */
diff --git a/include/linux/phy/phy-props.h b/include/linux/phy/phy-props.h
new file mode 100644
index 000000000000..11f36738165f
--- /dev/null
+++ b/include/linux/phy/phy-props.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * phy-provider.h -- Generic PHY properties
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+#ifndef __PHY_PROPS_H
+#define __PHY_PROPS_H
+
+#include <linux/phy/phy-dp.h>
+#include <linux/phy/phy-hdmi.h>
+#include <linux/phy/phy-lvds.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
+enum phy_mode {
+ PHY_MODE_INVALID,
+ PHY_MODE_USB_HOST,
+ PHY_MODE_USB_HOST_LS,
+ PHY_MODE_USB_HOST_FS,
+ PHY_MODE_USB_HOST_HS,
+ PHY_MODE_USB_HOST_SS,
+ PHY_MODE_USB_DEVICE,
+ PHY_MODE_USB_DEVICE_LS,
+ PHY_MODE_USB_DEVICE_FS,
+ PHY_MODE_USB_DEVICE_HS,
+ PHY_MODE_USB_DEVICE_SS,
+ PHY_MODE_USB_OTG,
+ PHY_MODE_UFS_HS_A,
+ PHY_MODE_UFS_HS_B,
+ PHY_MODE_PCIE,
+ PHY_MODE_ETHERNET,
+ PHY_MODE_MIPI_DPHY,
+ PHY_MODE_SATA,
+ PHY_MODE_LVDS,
+ PHY_MODE_DP,
+ PHY_MODE_HDMI,
+};
+
+enum phy_media {
+ PHY_MEDIA_DEFAULT,
+ PHY_MEDIA_SR,
+ PHY_MEDIA_DAC,
+};
+
+enum phy_ufs_state {
+ PHY_UFS_HIBERN8_ENTER,
+ PHY_UFS_HIBERN8_EXIT,
+};
+
+union phy_notify {
+ enum phy_ufs_state ufs_state;
+};
+
+/**
+ * union phy_configure_opts - Opaque generic phy configuration
+ *
+ * @mipi_dphy: Configuration set applicable for phys supporting
+ * the MIPI_DPHY phy mode.
+ * @dp: Configuration set applicable for phys supporting
+ * the DisplayPort protocol.
+ * @lvds: Configuration set applicable for phys supporting
+ * the LVDS phy mode.
+ * @hdmi: Configuration set applicable for phys supporting
+ * the HDMI phy mode.
+ */
+union phy_configure_opts {
+ struct phy_configure_opts_mipi_dphy mipi_dphy;
+ struct phy_configure_opts_dp dp;
+ struct phy_configure_opts_lvds lvds;
+ struct phy_configure_opts_hdmi hdmi;
+};
+
+#endif /* __PHY_PROPS_H */
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index ea47975e288a..f208edd25afe 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -1,246 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * phy.h -- generic phy header file
+ * phy.h -- Generic PHY consumer API
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Kishon Vijay Abraham I <kishon@ti.com>
*/
-#ifndef __DRIVERS_PHY_H
-#define __DRIVERS_PHY_H
+#ifndef __PHY_CONSUMER_H
+#define __PHY_CONSUMER_H
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/device.h>
-#include <linux/pm_runtime.h>
-#include <linux/regulator/consumer.h>
+#include <linux/phy/phy-props.h>
-#include <linux/phy/phy-dp.h>
-#include <linux/phy/phy-hdmi.h>
-#include <linux/phy/phy-lvds.h>
-#include <linux/phy/phy-mipi-dphy.h>
+#include "../../../drivers/phy/phy-provider.h"
+struct device;
+struct device_node;
struct phy;
-enum phy_mode {
- PHY_MODE_INVALID,
- PHY_MODE_USB_HOST,
- PHY_MODE_USB_HOST_LS,
- PHY_MODE_USB_HOST_FS,
- PHY_MODE_USB_HOST_HS,
- PHY_MODE_USB_HOST_SS,
- PHY_MODE_USB_DEVICE,
- PHY_MODE_USB_DEVICE_LS,
- PHY_MODE_USB_DEVICE_FS,
- PHY_MODE_USB_DEVICE_HS,
- PHY_MODE_USB_DEVICE_SS,
- PHY_MODE_USB_OTG,
- PHY_MODE_UFS_HS_A,
- PHY_MODE_UFS_HS_B,
- PHY_MODE_PCIE,
- PHY_MODE_ETHERNET,
- PHY_MODE_MIPI_DPHY,
- PHY_MODE_SATA,
- PHY_MODE_LVDS,
- PHY_MODE_DP,
- PHY_MODE_HDMI,
-};
-
-enum phy_media {
- PHY_MEDIA_DEFAULT,
- PHY_MEDIA_SR,
- PHY_MEDIA_DAC,
-};
-
-enum phy_ufs_state {
- PHY_UFS_HIBERN8_ENTER,
- PHY_UFS_HIBERN8_EXIT,
-};
-
-union phy_notify {
- enum phy_ufs_state ufs_state;
-};
-
-/**
- * union phy_configure_opts - Opaque generic phy configuration
- *
- * @mipi_dphy: Configuration set applicable for phys supporting
- * the MIPI_DPHY phy mode.
- * @dp: Configuration set applicable for phys supporting
- * the DisplayPort protocol.
- * @lvds: Configuration set applicable for phys supporting
- * the LVDS phy mode.
- * @hdmi: Configuration set applicable for phys supporting
- * the HDMI phy mode.
- */
-union phy_configure_opts {
- struct phy_configure_opts_mipi_dphy mipi_dphy;
- struct phy_configure_opts_dp dp;
- struct phy_configure_opts_lvds lvds;
- struct phy_configure_opts_hdmi hdmi;
-};
-
-/**
- * struct phy_ops - set of function pointers for performing phy operations
- * @init: operation to be performed for initializing phy
- * @exit: operation to be performed while exiting
- * @power_on: powering on the phy
- * @power_off: powering off the phy
- * @set_mode: set the mode of the phy
- * @set_media: set the media type of the phy (optional)
- * @set_speed: set the speed of the phy (optional)
- * @reset: resetting the phy
- * @calibrate: calibrate the phy
- * @notify_phystate: notify and configure the phy for a particular state
- * @release: ops to be performed while the consumer relinquishes the PHY
- * @owner: the module owner containing the ops
- */
-struct phy_ops {
- int (*init)(struct phy *phy);
- int (*exit)(struct phy *phy);
- int (*power_on)(struct phy *phy);
- int (*power_off)(struct phy *phy);
- int (*set_mode)(struct phy *phy, enum phy_mode mode, int submode);
- int (*set_media)(struct phy *phy, enum phy_media media);
- int (*set_speed)(struct phy *phy, int speed);
-
- /**
- * @configure:
- *
- * Optional.
- *
- * Used to change the PHY parameters. phy_init() must have
- * been called on the phy.
- *
- * Returns: 0 if successful, an negative error code otherwise
- */
- int (*configure)(struct phy *phy, union phy_configure_opts *opts);
-
- /**
- * @validate:
- *
- * Optional.
- *
- * Used to check that the current set of parameters can be
- * handled by the phy. Implementations are free to tune the
- * parameters passed as arguments if needed by some
- * implementation detail or constraints. It must not change
- * any actual configuration of the PHY, so calling it as many
- * times as deemed fit by the consumer must have no side
- * effect.
- *
- * Returns: 0 if the configuration can be applied, an negative
- * error code otherwise
- */
- int (*validate)(struct phy *phy, enum phy_mode mode, int submode,
- union phy_configure_opts *opts);
- int (*reset)(struct phy *phy);
- int (*calibrate)(struct phy *phy);
-
- /* notify phy connect status change */
- int (*connect)(struct phy *phy, int port);
- int (*disconnect)(struct phy *phy, int port);
-
- int (*notify_phystate)(struct phy *phy, union phy_notify state);
- void (*release)(struct phy *phy);
- struct module *owner;
-};
-
-/**
- * struct phy_attrs - represents phy attributes
- * @bus_width: Data path width implemented by PHY
- * @max_link_rate: Maximum link rate supported by PHY (units to be decided by producer and consumer)
- * @mode: PHY mode
- */
-struct phy_attrs {
- u32 bus_width;
- u32 max_link_rate;
- enum phy_mode mode;
-};
-
-/**
- * struct phy - represents the phy device
- * @dev: phy device
- * @id: id of the phy device
- * @ops: function pointers for performing phy operations
- * @mutex: mutex to protect phy_ops
- * @lockdep_key: lockdep information for this mutex
- * @init_count: used to protect when the PHY is used by multiple consumers
- * @power_count: used to protect when the PHY is used by multiple consumers
- * @attrs: used to specify PHY specific attributes
- * @pwr: power regulator associated with the phy
- * @debugfs: debugfs directory
- */
-struct phy {
- struct device dev;
- int id;
- const struct phy_ops *ops;
- struct mutex mutex;
- struct lock_class_key lockdep_key;
- int init_count;
- int power_count;
- struct phy_attrs attrs;
- struct regulator *pwr;
- struct dentry *debugfs;
-};
-
-/**
- * struct phy_provider - represents the phy provider
- * @dev: phy provider device
- * @children: can be used to override the default (dev->of_node) child node
- * @owner: the module owner having of_xlate
- * @list: to maintain a linked list of PHY providers
- * @of_xlate: function pointer to obtain phy instance from phy pointer
- */
-struct phy_provider {
- struct device *dev;
- struct device_node *children;
- struct module *owner;
- struct list_head list;
- struct phy * (*of_xlate)(struct device *dev,
- const struct of_phandle_args *args);
-};
-
-/**
- * struct phy_lookup - PHY association in list of phys managed by the phy driver
- * @node: list node
- * @dev_id: the device of the association
- * @con_id: connection ID string on device
- * @phy: the phy of the association
- */
-struct phy_lookup {
- struct list_head node;
- const char *dev_id;
- const char *con_id;
- struct phy *phy;
-};
-
-#define to_phy(a) (container_of((a), struct phy, dev))
-
-#define of_phy_provider_register(dev, xlate) \
- __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
-
-#define devm_of_phy_provider_register(dev, xlate) \
- __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
-
-#define of_phy_provider_register_full(dev, children, xlate) \
- __of_phy_provider_register(dev, children, THIS_MODULE, xlate)
-
-#define devm_of_phy_provider_register_full(dev, children, xlate) \
- __devm_of_phy_provider_register(dev, children, THIS_MODULE, xlate)
-
-static inline void phy_set_drvdata(struct phy *phy, void *data)
-{
- dev_set_drvdata(&phy->dev, data);
-}
-
-static inline void *phy_get_drvdata(struct phy *phy)
-{
- return dev_get_drvdata(&phy->dev);
-}
-
#if IS_ENABLED(CONFIG_GENERIC_PHY)
+struct phy *phy_get(struct device *dev, const char *string);
+struct phy *devm_phy_get(struct device *dev, const char *string);
+struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+ const char *con_id);
+struct phy *devm_of_phy_optional_get(struct device *dev, struct device_node *np,
+ const char *con_id);
+struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
+ int index);
+void of_phy_put(struct phy *phy);
+void phy_put(struct device *dev, struct phy *phy);
+void devm_phy_put(struct device *dev, struct phy *phy);
+struct phy *of_phy_get(struct device_node *np, const char *con_id);
+
int phy_pm_runtime_get(struct phy *phy);
int phy_pm_runtime_get_sync(struct phy *phy);
void phy_pm_runtime_put(struct phy *phy);
@@ -257,59 +49,69 @@ int phy_set_speed(struct phy *phy, int speed);
int phy_configure(struct phy *phy, union phy_configure_opts *opts);
int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts);
-
-static inline enum phy_mode phy_get_mode(struct phy *phy)
-{
- return phy->attrs.mode;
-}
+enum phy_mode phy_get_mode(struct phy *phy);
int phy_reset(struct phy *phy);
int phy_calibrate(struct phy *phy);
int phy_notify_connect(struct phy *phy, int port);
int phy_notify_disconnect(struct phy *phy, int port);
int phy_notify_state(struct phy *phy, union phy_notify state);
-static inline int phy_get_bus_width(struct phy *phy)
+int phy_get_bus_width(struct phy *phy);
+void phy_set_bus_width(struct phy *phy, int bus_width);
+#else
+static inline struct phy *phy_get(struct device *dev, const char *string)
{
- return phy->attrs.bus_width;
+ return ERR_PTR(-ENOSYS);
}
-static inline void phy_set_bus_width(struct phy *phy, int bus_width)
+
+static inline struct phy *devm_phy_get(struct device *dev, const char *string)
{
- phy->attrs.bus_width = bus_width;
+ return ERR_PTR(-ENOSYS);
}
-struct phy *phy_get(struct device *dev, const char *string);
-struct phy *devm_phy_get(struct device *dev, const char *string);
-struct phy *devm_phy_optional_get(struct device *dev, const char *string);
-struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
- const char *con_id);
-struct phy *devm_of_phy_optional_get(struct device *dev, struct device_node *np,
- const char *con_id);
-struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
- int index);
-void of_phy_put(struct phy *phy);
-void phy_put(struct device *dev, struct phy *phy);
-void devm_phy_put(struct device *dev, struct phy *phy);
-struct phy *of_phy_get(struct device_node *np, const char *con_id);
-struct phy *of_phy_simple_xlate(struct device *dev,
- const struct of_phandle_args *args);
-struct phy *phy_create(struct device *dev, struct device_node *node,
- const struct phy_ops *ops);
-struct phy *devm_phy_create(struct device *dev, struct device_node *node,
- const struct phy_ops *ops);
-void phy_destroy(struct phy *phy);
-void devm_phy_destroy(struct device *dev, struct phy *phy);
-struct phy_provider *__of_phy_provider_register(struct device *dev,
- struct device_node *children, struct module *owner,
- struct phy * (*of_xlate)(struct device *dev,
- const struct of_phandle_args *args));
-struct phy_provider *__devm_of_phy_provider_register(struct device *dev,
- struct device_node *children, struct module *owner,
- struct phy * (*of_xlate)(struct device *dev,
- const struct of_phandle_args *args));
-void of_phy_provider_unregister(struct phy_provider *phy_provider);
-void devm_of_phy_provider_unregister(struct device *dev,
- struct phy_provider *phy_provider);
-int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
-void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
-#else
+
+static inline struct phy *devm_phy_optional_get(struct device *dev,
+ const char *string)
+{
+ return NULL;
+}
+
+static inline struct phy *devm_of_phy_get(struct device *dev,
+ struct device_node *np,
+ const char *con_id)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct phy *devm_of_phy_optional_get(struct device *dev,
+ struct device_node *np,
+ const char *con_id)
+{
+ return NULL;
+}
+
+static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
+ struct device_node *np,
+ int index)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline void of_phy_put(struct phy *phy)
+{
+}
+
+static inline void phy_put(struct device *dev, struct phy *phy)
+{
+}
+
+static inline void devm_phy_put(struct device *dev, struct phy *phy)
+{
+}
+
+static inline struct phy *of_phy_get(struct device_node *np, const char *con_id)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline int phy_pm_runtime_get(struct phy *phy)
{
if (!phy)
@@ -388,61 +190,59 @@ static inline int phy_set_speed(struct phy *phy, int speed)
return -ENODEV;
}
-static inline enum phy_mode phy_get_mode(struct phy *phy)
-{
- return PHY_MODE_INVALID;
-}
-
-static inline int phy_reset(struct phy *phy)
+static inline int phy_configure(struct phy *phy,
+ union phy_configure_opts *opts)
{
if (!phy)
return 0;
return -ENOSYS;
}
-static inline int phy_calibrate(struct phy *phy)
+static inline int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts)
{
if (!phy)
return 0;
return -ENOSYS;
}
-static inline int phy_notify_connect(struct phy *phy, int index)
+static inline enum phy_mode phy_get_mode(struct phy *phy)
+{
+ return PHY_MODE_INVALID;
+}
+
+static inline int phy_reset(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
-static inline int phy_notify_disconnect(struct phy *phy, int index)
+static inline int phy_calibrate(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
-static inline int phy_notify_state(struct phy *phy, union phy_notify state)
+static inline int phy_notify_connect(struct phy *phy, int index)
{
if (!phy)
return 0;
return -ENOSYS;
}
-static inline int phy_configure(struct phy *phy,
- union phy_configure_opts *opts)
+static inline int phy_notify_disconnect(struct phy *phy, int index)
{
if (!phy)
return 0;
-
return -ENOSYS;
}
-static inline int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
- union phy_configure_opts *opts)
+static inline int phy_notify_state(struct phy *phy, union phy_notify state)
{
if (!phy)
return 0;
-
return -ENOSYS;
}
@@ -453,122 +253,7 @@ static inline int phy_get_bus_width(struct phy *phy)
static inline void phy_set_bus_width(struct phy *phy, int bus_width)
{
- return;
-}
-
-static inline struct phy *phy_get(struct device *dev, const char *string)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy *devm_phy_get(struct device *dev, const char *string)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy *devm_phy_optional_get(struct device *dev,
- const char *string)
-{
- return NULL;
-}
-
-static inline struct phy *devm_of_phy_get(struct device *dev,
- struct device_node *np,
- const char *con_id)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy *devm_of_phy_optional_get(struct device *dev,
- struct device_node *np,
- const char *con_id)
-{
- return NULL;
-}
-
-static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
- struct device_node *np,
- int index)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline void of_phy_put(struct phy *phy)
-{
-}
-
-static inline void phy_put(struct device *dev, struct phy *phy)
-{
-}
-
-static inline void devm_phy_put(struct device *dev, struct phy *phy)
-{
-}
-
-static inline struct phy *of_phy_get(struct device_node *np, const char *con_id)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy *of_phy_simple_xlate(struct device *dev,
- const struct of_phandle_args *args)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy *phy_create(struct device *dev,
- struct device_node *node,
- const struct phy_ops *ops)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy *devm_phy_create(struct device *dev,
- struct device_node *node,
- const struct phy_ops *ops)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline void phy_destroy(struct phy *phy)
-{
-}
-
-static inline void devm_phy_destroy(struct device *dev, struct phy *phy)
-{
-}
-
-static inline struct phy_provider *__of_phy_provider_register(
- struct device *dev, struct device_node *children, struct module *owner,
- struct phy * (*of_xlate)(struct device *dev,
- const struct of_phandle_args *args))
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline struct phy_provider *__devm_of_phy_provider_register(struct device
- *dev, struct device_node *children, struct module *owner,
- struct phy * (*of_xlate)(struct device *dev,
- const struct of_phandle_args *args))
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline void of_phy_provider_unregister(struct phy_provider *phy_provider)
-{
-}
-
-static inline void devm_of_phy_provider_unregister(struct device *dev,
- struct phy_provider *phy_provider)
-{
-}
-static inline int
-phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
-{
- return 0;
}
-static inline void phy_remove_lookup(struct phy *phy, const char *con_id,
- const char *dev_id) { }
-#endif
+#endif /* IS_ENABLED(CONFIG_GENERIC_PHY) */
-#endif /* __DRIVERS_PHY_H */
+#endif /* __PHY_CONSUMER_H */
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v7 1/4] drm/msm/hdmi: switch to generic PHY subsystem
From: Dmitry Baryshkov @ 2026-03-23 22:56 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Vinod Koul, Neil Armstrong
Cc: linux-kernel, linux-arm-msm, dri-devel, freedreno, linux-phy,
Dmitry Baryshkov, Konrad Dybcio
In-Reply-To: <20260324-fd-hdmi-phy-v7-0-b41dde8d83b8@oss.qualcomm.com>
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Change the MSM HDMI driver to use generic PHY subsystem. Moving PHY
drivers allows better code sharing with the rest of the PHY system.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Acked-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/gpu/drm/msm/Makefile | 7 -
drivers/gpu/drm/msm/hdmi/hdmi.c | 58 +-
drivers/gpu/drm/msm/hdmi/hdmi.h | 80 +--
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 80 ++-
drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 225 -------
drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c | 51 --
drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c | 761 ----------------------
drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c | 765 -----------------------
drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c | 141 -----
drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c | 44 --
drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c | 460 --------------
drivers/gpu/drm/msm/registers/display/hdmi.xml | 537 ----------------
drivers/phy/qualcomm/Kconfig | 24 +
drivers/phy/qualcomm/Makefile | 14 +
drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c | 71 +++
drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c | 462 ++++++++++++++
drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c | 186 ++++++
drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c | 212 +++++++
drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h | 59 ++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c | 185 ++++++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c | 440 +++++++++++++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c | 489 +++++++++++++++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h | 49 ++
23 files changed, 2234 insertions(+), 3166 deletions(-)
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 8b94c5f1cb68..caad271a0283 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -36,13 +36,6 @@ msm-display-$(CONFIG_DRM_MSM_HDMI) += \
hdmi/hdmi_bridge.o \
hdmi/hdmi_hpd.o \
hdmi/hdmi_i2c.o \
- hdmi/hdmi_phy.o \
- hdmi/hdmi_phy_8960.o \
- hdmi/hdmi_phy_8996.o \
- hdmi/hdmi_phy_8998.o \
- hdmi/hdmi_phy_8x60.o \
- hdmi/hdmi_phy_8x74.o \
- hdmi/hdmi_pll_8960.o \
msm-display-$(CONFIG_DRM_MSM_MDP4) += \
disp/mdp4/mdp4_crtc.o \
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 5afac09c0d33..0b54b9137da0 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -10,6 +10,7 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_of.h>
@@ -76,44 +77,6 @@ static void msm_hdmi_destroy(struct hdmi *hdmi)
msm_hdmi_i2c_destroy(hdmi->i2c);
}
-static void msm_hdmi_put_phy(struct hdmi *hdmi)
-{
- if (hdmi->phy_dev) {
- put_device(hdmi->phy_dev);
- hdmi->phy = NULL;
- hdmi->phy_dev = NULL;
- }
-}
-
-static int msm_hdmi_get_phy(struct hdmi *hdmi)
-{
- struct platform_device *pdev = hdmi->pdev;
- struct platform_device *phy_pdev;
- struct device_node *phy_node;
-
- phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0);
- if (!phy_node) {
- DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n");
- return -ENXIO;
- }
-
- phy_pdev = of_find_device_by_node(phy_node);
- of_node_put(phy_node);
-
- if (!phy_pdev)
- return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");
-
- hdmi->phy = platform_get_drvdata(phy_pdev);
- if (!hdmi->phy) {
- put_device(&phy_pdev->dev);
- return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");
- }
-
- hdmi->phy_dev = &phy_pdev->dev;
-
- return 0;
-}
-
/* construct hdmi at bind/probe time, grab all the resources. If
* we are to EPROBE_DEFER we want to do it here, rather than later
* at modeset_init() time
@@ -357,36 +320,31 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
if (hdmi->hpd_gpiod)
gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");
- ret = msm_hdmi_get_phy(hdmi);
- if (ret) {
+ hdmi->phy = devm_phy_get(&pdev->dev, NULL);
+ if (IS_ERR(hdmi->phy)) {
DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n");
- return ret;
+ return PTR_ERR(hdmi->phy);
}
ret = devm_pm_runtime_enable(&pdev->dev);
if (ret)
- goto err_put_phy;
+ goto err;
platform_set_drvdata(pdev, hdmi);
ret = component_add(&pdev->dev, &msm_hdmi_ops);
if (ret)
- goto err_put_phy;
+ goto err;
return 0;
-err_put_phy:
- msm_hdmi_put_phy(hdmi);
+err:
return ret;
}
static void msm_hdmi_dev_remove(struct platform_device *pdev)
{
- struct hdmi *hdmi = dev_get_drvdata(&pdev->dev);
-
component_del(&pdev->dev, &msm_hdmi_ops);
-
- msm_hdmi_put_phy(hdmi);
}
static int msm_hdmi_runtime_suspend(struct device *dev)
@@ -454,12 +412,10 @@ static struct platform_driver msm_hdmi_driver = {
void __init msm_hdmi_register(void)
{
- msm_hdmi_phy_driver_register();
platform_driver_register(&msm_hdmi_driver);
}
void __exit msm_hdmi_unregister(void)
{
platform_driver_unregister(&msm_hdmi_driver);
- msm_hdmi_phy_driver_unregister();
}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 02cfd46df594..7a73441ebb23 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -19,7 +19,6 @@
#include "msm_drv.h"
#include "hdmi.xml.h"
-struct hdmi_phy;
struct hdmi_platform_config;
struct hdmi_audio {
@@ -55,8 +54,7 @@ struct hdmi {
struct gpio_desc *hpd_gpiod;
- struct hdmi_phy *phy;
- struct device *phy_dev;
+ struct phy *phy;
struct i2c_adapter *i2c;
struct drm_connector *connector;
@@ -117,82 +115,6 @@ static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, u32 reg)
return readl(hdmi->qfprom_mmio + reg);
}
-/*
- * hdmi phy:
- */
-
-enum hdmi_phy_type {
- MSM_HDMI_PHY_8x60,
- MSM_HDMI_PHY_8960,
- MSM_HDMI_PHY_8x74,
- MSM_HDMI_PHY_8996,
- MSM_HDMI_PHY_8998,
- MSM_HDMI_PHY_MAX,
-};
-
-struct hdmi_phy_cfg {
- enum hdmi_phy_type type;
- void (*powerup)(struct hdmi_phy *phy, unsigned long int pixclock);
- void (*powerdown)(struct hdmi_phy *phy);
- const char * const *reg_names;
- int num_regs;
- const char * const *clk_names;
- int num_clks;
-};
-
-extern const struct hdmi_phy_cfg msm_hdmi_phy_8x60_cfg;
-extern const struct hdmi_phy_cfg msm_hdmi_phy_8960_cfg;
-extern const struct hdmi_phy_cfg msm_hdmi_phy_8x74_cfg;
-extern const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg;
-extern const struct hdmi_phy_cfg msm_hdmi_phy_8998_cfg;
-
-struct hdmi_phy {
- struct platform_device *pdev;
- void __iomem *mmio;
- struct hdmi_phy_cfg *cfg;
- const struct hdmi_phy_funcs *funcs;
- struct regulator_bulk_data *regs;
- struct clk **clks;
-};
-
-static inline void hdmi_phy_write(struct hdmi_phy *phy, u32 reg, u32 data)
-{
- writel(data, phy->mmio + reg);
-}
-
-static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg)
-{
- return readl(phy->mmio + reg);
-}
-
-int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy);
-void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy);
-void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock);
-void msm_hdmi_phy_powerdown(struct hdmi_phy *phy);
-void __init msm_hdmi_phy_driver_register(void);
-void __exit msm_hdmi_phy_driver_unregister(void);
-
-#ifdef CONFIG_COMMON_CLK
-int msm_hdmi_pll_8960_init(struct platform_device *pdev);
-int msm_hdmi_pll_8996_init(struct platform_device *pdev);
-int msm_hdmi_pll_8998_init(struct platform_device *pdev);
-#else
-static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev)
-{
- return -ENODEV;
-}
-
-static inline int msm_hdmi_pll_8996_init(struct platform_device *pdev)
-{
- return -ENODEV;
-}
-
-static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
-{
- return -ENODEV;
-}
-#endif
-
/*
* audio:
*/
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 98cd490e7ab0..5062ccf2e3ff 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -5,6 +5,7 @@
*/
#include <linux/delay.h>
+#include <linux/phy/phy.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_edid.h>
#include <drm/display/drm_hdmi_helper.h>
@@ -13,43 +14,6 @@
#include "msm_kms.h"
#include "hdmi.h"
-static void msm_hdmi_power_on(struct drm_bridge *bridge)
-{
- struct drm_device *dev = bridge->dev;
- struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
- struct hdmi *hdmi = hdmi_bridge->hdmi;
- int ret;
-
- pm_runtime_resume_and_get(&hdmi->pdev->dev);
-
- if (hdmi->extp_clk) {
- DBG("pixclock: %lu", hdmi->pixclock);
- ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
- if (ret)
- DRM_DEV_ERROR(dev->dev, "failed to set extp clk rate: %d\n", ret);
-
- ret = clk_prepare_enable(hdmi->extp_clk);
- if (ret)
- DRM_DEV_ERROR(dev->dev, "failed to enable extp clk: %d\n", ret);
- }
-}
-
-static void power_off(struct drm_bridge *bridge)
-{
- struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
- struct hdmi *hdmi = hdmi_bridge->hdmi;
-
- /* TODO do we need to wait for final vblank somewhere before
- * cutting the clocks?
- */
- mdelay(16 + 4);
-
- if (hdmi->extp_clk)
- clk_disable_unprepare(hdmi->extp_clk);
-
- pm_runtime_put(&hdmi->pdev->dev);
-}
-
#define AVI_IFRAME_LINE_NUMBER 1
#define SPD_IFRAME_LINE_NUMBER 1
#define VENSPEC_IFRAME_LINE_NUMBER 3
@@ -287,11 +251,12 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
- struct hdmi_phy *phy = hdmi->phy;
struct drm_encoder *encoder = bridge->encoder;
struct drm_connector *connector;
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
+ union phy_configure_opts phy_opts;
+ int ret;
DBG("power up");
@@ -305,8 +270,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
mutex_lock(&hdmi->state_mutex);
if (!hdmi->power_on) {
- msm_hdmi_phy_resource_enable(phy);
- msm_hdmi_power_on(bridge);
+ phy_init(hdmi->phy);
+ pm_runtime_get_sync(&hdmi->pdev->dev);
hdmi->power_on = true;
}
mutex_unlock(&hdmi->state_mutex);
@@ -316,7 +281,23 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
- msm_hdmi_phy_powerup(phy, hdmi->pixclock);
+ phy_opts.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+ phy_opts.hdmi.bpc = 8;
+ phy_configure(hdmi->phy, &phy_opts);
+
+ ret = phy_power_on(hdmi->phy);
+ if (WARN_ON(ret))
+ return;
+
+ if (hdmi->extp_clk) {
+ ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
+ if (ret)
+ DRM_DEV_ERROR(bridge->dev->dev, "failed to set extp clk rate: %d\n", ret);
+
+ ret = clk_prepare_enable(hdmi->extp_clk);
+ if (ret)
+ DRM_DEV_ERROR(bridge->dev->dev, "failed to enable extp clk: %d\n", ret);
+ }
msm_hdmi_set_mode(hdmi, true);
@@ -329,7 +310,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
- struct hdmi_phy *phy = hdmi->phy;
if (hdmi->hdcp_ctrl)
msm_hdmi_hdcp_off(hdmi->hdcp_ctrl);
@@ -340,14 +320,24 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
mutex_lock(&hdmi->state_mutex);
msm_hdmi_set_mode(hdmi, hdmi->hpd_enabled);
- msm_hdmi_phy_powerdown(phy);
+ /* TODO do we need to wait for final vblank somewhere before
+ * cutting the clocks?
+ */
+ mdelay(16 + 4);
+
+ if (hdmi->extp_clk)
+ clk_disable_unprepare(hdmi->extp_clk);
+
+ phy_power_off(hdmi->phy);
if (hdmi->power_on) {
- power_off(bridge);
+
+ pm_runtime_put(&hdmi->pdev->dev);
+
hdmi->power_on = false;
if (hdmi->connector->display_info.is_hdmi)
msm_hdmi_audio_update(hdmi);
- msm_hdmi_phy_resource_disable(phy);
+ phy_exit(hdmi->phy);
}
mutex_unlock(&hdmi->state_mutex);
}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
deleted file mode 100644
index 667573f1db7c..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
+++ /dev/null
@@ -1,225 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/of.h>
-#include <linux/platform_device.h>
-
-#include "hdmi.h"
-
-static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)
-{
- struct hdmi_phy_cfg *cfg = phy->cfg;
- struct device *dev = &phy->pdev->dev;
- int i, ret;
-
- phy->regs = devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]),
- GFP_KERNEL);
- if (!phy->regs)
- return -ENOMEM;
-
- phy->clks = devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]),
- GFP_KERNEL);
- if (!phy->clks)
- return -ENOMEM;
-
- for (i = 0; i < cfg->num_regs; i++)
- phy->regs[i].supply = cfg->reg_names[i];
-
- ret = devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret);
-
- return ret;
- }
-
- for (i = 0; i < cfg->num_clks; i++) {
- struct clk *clk;
-
- clk = msm_clk_get(phy->pdev, cfg->clk_names[i]);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n",
- cfg->clk_names[i], ret);
- return ret;
- }
-
- phy->clks[i] = clk;
- }
-
- return 0;
-}
-
-int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy)
-{
- struct hdmi_phy_cfg *cfg = phy->cfg;
- struct device *dev = &phy->pdev->dev;
- int i, ret = 0;
-
- ret = pm_runtime_resume_and_get(dev);
- if (ret) {
- DRM_DEV_ERROR(dev, "runtime resume failed: %d\n", ret);
- return ret;
- }
-
- ret = regulator_bulk_enable(cfg->num_regs, phy->regs);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret);
- return ret;
- }
-
- for (i = 0; i < cfg->num_clks; i++) {
- ret = clk_prepare_enable(phy->clks[i]);
- if (ret)
- DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n",
- cfg->clk_names[i], ret);
- }
-
- return ret;
-}
-
-void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)
-{
- struct hdmi_phy_cfg *cfg = phy->cfg;
- struct device *dev = &phy->pdev->dev;
- int i;
-
- for (i = cfg->num_clks - 1; i >= 0; i--)
- clk_disable_unprepare(phy->clks[i]);
-
- regulator_bulk_disable(cfg->num_regs, phy->regs);
-
- pm_runtime_put_sync(dev);
-}
-
-void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock)
-{
- if (!phy || !phy->cfg->powerup)
- return;
-
- phy->cfg->powerup(phy, pixclock);
-}
-
-void msm_hdmi_phy_powerdown(struct hdmi_phy *phy)
-{
- if (!phy || !phy->cfg->powerdown)
- return;
-
- phy->cfg->powerdown(phy);
-}
-
-static int msm_hdmi_phy_pll_init(struct platform_device *pdev,
- enum hdmi_phy_type type)
-{
- int ret;
-
- switch (type) {
- case MSM_HDMI_PHY_8960:
- ret = msm_hdmi_pll_8960_init(pdev);
- break;
- case MSM_HDMI_PHY_8996:
- ret = msm_hdmi_pll_8996_init(pdev);
- break;
- case MSM_HDMI_PHY_8998:
- ret = msm_hdmi_pll_8998_init(pdev);
- break;
- /*
- * we don't have PLL support for these, don't report an error for now
- */
- case MSM_HDMI_PHY_8x60:
- case MSM_HDMI_PHY_8x74:
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static int msm_hdmi_phy_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct hdmi_phy *phy;
- int ret;
-
- phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
- if (!phy)
- return -ENODEV;
-
- phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
- if (!phy->cfg)
- return -ENODEV;
-
- phy->mmio = msm_ioremap(pdev, "hdmi_phy");
- if (IS_ERR(phy->mmio)) {
- DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
- return -ENOMEM;
- }
-
- phy->pdev = pdev;
-
- ret = msm_hdmi_phy_resource_init(phy);
- if (ret)
- return ret;
-
- pm_runtime_enable(&pdev->dev);
-
- ret = msm_hdmi_phy_resource_enable(phy);
- if (ret)
- return ret;
-
- ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
- if (ret) {
- DRM_DEV_ERROR(dev, "couldn't init PLL\n");
- msm_hdmi_phy_resource_disable(phy);
- return ret;
- }
-
- msm_hdmi_phy_resource_disable(phy);
-
- platform_set_drvdata(pdev, phy);
-
- return 0;
-}
-
-static void msm_hdmi_phy_remove(struct platform_device *pdev)
-{
- pm_runtime_disable(&pdev->dev);
-}
-
-static const struct of_device_id msm_hdmi_phy_dt_match[] = {
- { .compatible = "qcom,hdmi-phy-8660",
- .data = &msm_hdmi_phy_8x60_cfg },
- { .compatible = "qcom,hdmi-phy-8960",
- .data = &msm_hdmi_phy_8960_cfg },
- { .compatible = "qcom,hdmi-phy-8974",
- .data = &msm_hdmi_phy_8x74_cfg },
- { .compatible = "qcom,hdmi-phy-8084",
- .data = &msm_hdmi_phy_8x74_cfg },
- { .compatible = "qcom,hdmi-phy-8996",
- .data = &msm_hdmi_phy_8996_cfg },
- { .compatible = "qcom,hdmi-phy-8998",
- .data = &msm_hdmi_phy_8998_cfg },
- {}
-};
-
-static struct platform_driver msm_hdmi_phy_platform_driver = {
- .probe = msm_hdmi_phy_probe,
- .remove = msm_hdmi_phy_remove,
- .driver = {
- .name = "msm_hdmi_phy",
- .of_match_table = msm_hdmi_phy_dt_match,
- },
-};
-
-void __init msm_hdmi_phy_driver_register(void)
-{
- platform_driver_register(&msm_hdmi_phy_platform_driver);
-}
-
-void __exit msm_hdmi_phy_driver_unregister(void)
-{
- platform_driver_unregister(&msm_hdmi_phy_platform_driver);
-}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
deleted file mode 100644
index cf90a0c1f822..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- */
-
-#include "hdmi.h"
-
-static void hdmi_phy_8960_powerup(struct hdmi_phy *phy,
- unsigned long int pixclock)
-{
- DBG("pixclock: %lu", pixclock);
-
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG0, 0x1b);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG1, 0xf2);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG4, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG5, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG6, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG7, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG8, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG9, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG10, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG11, 0x00);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG3, 0x20);
-}
-
-static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy)
-{
- DBG("");
-
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x7f);
-}
-
-static const char * const hdmi_phy_8960_reg_names[] = {
- "core-vdda",
-};
-
-static const char * const hdmi_phy_8960_clk_names[] = {
- "slave_iface",
-};
-
-const struct hdmi_phy_cfg msm_hdmi_phy_8960_cfg = {
- .type = MSM_HDMI_PHY_8960,
- .powerup = hdmi_phy_8960_powerup,
- .powerdown = hdmi_phy_8960_powerdown,
- .reg_names = hdmi_phy_8960_reg_names,
- .num_regs = ARRAY_SIZE(hdmi_phy_8960_reg_names),
- .clk_names = hdmi_phy_8960_clk_names,
- .num_clks = ARRAY_SIZE(hdmi_phy_8960_clk_names),
-};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c
deleted file mode 100644
index 36e928b0fd5a..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c
+++ /dev/null
@@ -1,761 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/delay.h>
-
-#include "hdmi.h"
-
-#define HDMI_VCO_MAX_FREQ 12000000000UL
-#define HDMI_VCO_MIN_FREQ 8000000000UL
-
-#define HDMI_PCLK_MAX_FREQ 600000000
-#define HDMI_PCLK_MIN_FREQ 25000000
-
-#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL
-#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL
-#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL
-#define HDMI_CORECLK_DIV 5
-#define HDMI_DEFAULT_REF_CLOCK 19200000
-#define HDMI_PLL_CMP_CNT 1024
-
-#define HDMI_PLL_POLL_MAX_READS 100
-#define HDMI_PLL_POLL_TIMEOUT_US 150
-
-#define HDMI_NUM_TX_CHANNEL 4
-
-struct hdmi_pll_8996 {
- struct platform_device *pdev;
- struct clk_hw clk_hw;
-
- /* pll mmio base */
- void __iomem *mmio_qserdes_com;
- /* tx channel base */
- void __iomem *mmio_qserdes_tx[HDMI_NUM_TX_CHANNEL];
-};
-
-#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8996, clk_hw)
-
-struct hdmi_8996_phy_pll_reg_cfg {
- u32 tx_lx_lane_mode[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_tx_band[HDMI_NUM_TX_CHANNEL];
- u32 com_svs_mode_clk_sel;
- u32 com_hsclk_sel;
- u32 com_pll_cctrl_mode0;
- u32 com_pll_rctrl_mode0;
- u32 com_cp_ctrl_mode0;
- u32 com_dec_start_mode0;
- u32 com_div_frac_start1_mode0;
- u32 com_div_frac_start2_mode0;
- u32 com_div_frac_start3_mode0;
- u32 com_integloop_gain0_mode0;
- u32 com_integloop_gain1_mode0;
- u32 com_lock_cmp_en;
- u32 com_lock_cmp1_mode0;
- u32 com_lock_cmp2_mode0;
- u32 com_lock_cmp3_mode0;
- u32 com_core_clk_en;
- u32 com_coreclk_div;
- u32 com_vco_tune_ctrl;
-
- u32 tx_lx_tx_drv_lvl[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_tx_emp_post1_lvl[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_vmode_ctrl1[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_vmode_ctrl2[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_res_code_lane_tx[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_hp_pd_enables[HDMI_NUM_TX_CHANNEL];
-
- u32 phy_mode;
-};
-
-struct hdmi_8996_post_divider {
- u64 vco_freq;
- int hsclk_divsel;
- int vco_ratio;
- int tx_band_sel;
- int half_rate_mode;
-};
-
-static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8996 *pll)
-{
- return platform_get_drvdata(pll->pdev);
-}
-
-static inline void hdmi_pll_write(struct hdmi_pll_8996 *pll, int offset,
- u32 data)
-{
- writel(data, pll->mmio_qserdes_com + offset);
-}
-
-static inline u32 hdmi_pll_read(struct hdmi_pll_8996 *pll, int offset)
-{
- return readl(pll->mmio_qserdes_com + offset);
-}
-
-static inline void hdmi_tx_chan_write(struct hdmi_pll_8996 *pll, int channel,
- int offset, int data)
-{
- writel(data, pll->mmio_qserdes_tx[channel] + offset);
-}
-
-static inline u32 pll_get_cpctrl(u64 frac_start, unsigned long ref_clk,
- bool gen_ssc)
-{
- if ((frac_start != 0) || gen_ssc)
- return (11000000 / (ref_clk / 20));
-
- return 0x23;
-}
-
-static inline u32 pll_get_rctrl(u64 frac_start, bool gen_ssc)
-{
- if ((frac_start != 0) || gen_ssc)
- return 0x16;
-
- return 0x10;
-}
-
-static inline u32 pll_get_cctrl(u64 frac_start, bool gen_ssc)
-{
- if ((frac_start != 0) || gen_ssc)
- return 0x28;
-
- return 0x1;
-}
-
-static inline u32 pll_get_integloop_gain(u64 frac_start, u64 bclk, u32 ref_clk,
- bool gen_ssc)
-{
- int digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2;
- u64 base;
-
- if ((frac_start != 0) || gen_ssc)
- base = (64 * ref_clk) / HDMI_DEFAULT_REF_CLOCK;
- else
- base = (1022 * ref_clk) / 100;
-
- base <<= digclk_divsel;
-
- return (base <= 2046 ? base : 2046);
-}
-
-static inline u32 pll_get_pll_cmp(u64 fdata, unsigned long ref_clk)
-{
- u64 dividend = HDMI_PLL_CMP_CNT * fdata;
- u32 divisor = ref_clk * 10;
- u32 rem;
-
- rem = do_div(dividend, divisor);
- if (rem > (divisor >> 1))
- dividend++;
-
- return dividend - 1;
-}
-
-static inline u64 pll_cmp_to_fdata(u32 pll_cmp, unsigned long ref_clk)
-{
- u64 fdata = ((u64)pll_cmp) * ref_clk * 10;
-
- do_div(fdata, HDMI_PLL_CMP_CNT);
-
- return fdata;
-}
-
-static int pll_get_post_div(struct hdmi_8996_post_divider *pd, u64 bclk)
-{
- int ratio[] = { 2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35 };
- int hs_divsel[] = { 0, 4, 8, 12, 1, 5, 2, 9, 3, 13, 10, 7, 14, 11, 15 };
- int tx_band_sel[] = { 0, 1, 2, 3 };
- u64 vco_freq[60];
- u64 vco, vco_optimal;
- int half_rate_mode = 0;
- int vco_optimal_index, vco_freq_index;
- int i, j;
-
-retry:
- vco_optimal = HDMI_VCO_MAX_FREQ;
- vco_optimal_index = -1;
- vco_freq_index = 0;
- for (i = 0; i < 15; i++) {
- for (j = 0; j < 4; j++) {
- u32 ratio_mult = ratio[i] << tx_band_sel[j];
-
- vco = bclk >> half_rate_mode;
- vco *= ratio_mult;
- vco_freq[vco_freq_index++] = vco;
- }
- }
-
- for (i = 0; i < 60; i++) {
- u64 vco_tmp = vco_freq[i];
-
- if ((vco_tmp >= HDMI_VCO_MIN_FREQ) &&
- (vco_tmp <= vco_optimal)) {
- vco_optimal = vco_tmp;
- vco_optimal_index = i;
- }
- }
-
- if (vco_optimal_index == -1) {
- if (!half_rate_mode) {
- half_rate_mode = 1;
- goto retry;
- }
- } else {
- pd->vco_freq = vco_optimal;
- pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4];
- pd->vco_ratio = ratio[vco_optimal_index / 4];
- pd->hsclk_divsel = hs_divsel[vco_optimal_index / 4];
-
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int pll_calculate(unsigned long pix_clk, unsigned long ref_clk,
- struct hdmi_8996_phy_pll_reg_cfg *cfg)
-{
- struct hdmi_8996_post_divider pd;
- u64 bclk;
- u64 tmds_clk;
- u64 dec_start;
- u64 frac_start;
- u64 fdata;
- u32 pll_divisor;
- u32 rem;
- u32 cpctrl;
- u32 rctrl;
- u32 cctrl;
- u32 integloop_gain;
- u32 pll_cmp;
- int i, ret;
-
- /* bit clk = 10 * pix_clk */
- bclk = ((u64)pix_clk) * 10;
-
- if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
- tmds_clk = pix_clk >> 2;
- else
- tmds_clk = pix_clk;
-
- ret = pll_get_post_div(&pd, bclk);
- if (ret)
- return ret;
-
- dec_start = pd.vco_freq;
- pll_divisor = 4 * ref_clk;
- do_div(dec_start, pll_divisor);
-
- frac_start = pd.vco_freq * (1 << 20);
-
- rem = do_div(frac_start, pll_divisor);
- frac_start -= dec_start * (1 << 20);
- if (rem > (pll_divisor >> 1))
- frac_start++;
-
- cpctrl = pll_get_cpctrl(frac_start, ref_clk, false);
- rctrl = pll_get_rctrl(frac_start, false);
- cctrl = pll_get_cctrl(frac_start, false);
- integloop_gain = pll_get_integloop_gain(frac_start, bclk,
- ref_clk, false);
-
- fdata = pd.vco_freq;
- do_div(fdata, pd.vco_ratio);
-
- pll_cmp = pll_get_pll_cmp(fdata, ref_clk);
-
- DBG("VCO freq: %llu", pd.vco_freq);
- DBG("fdata: %llu", fdata);
- DBG("pix_clk: %lu", pix_clk);
- DBG("tmds clk: %llu", tmds_clk);
- DBG("HSCLK_SEL: %d", pd.hsclk_divsel);
- DBG("DEC_START: %llu", dec_start);
- DBG("DIV_FRAC_START: %llu", frac_start);
- DBG("PLL_CPCTRL: %u", cpctrl);
- DBG("PLL_RCTRL: %u", rctrl);
- DBG("PLL_CCTRL: %u", cctrl);
- DBG("INTEGLOOP_GAIN: %u", integloop_gain);
- DBG("TX_BAND: %d", pd.tx_band_sel);
- DBG("PLL_CMP: %u", pll_cmp);
-
- /* Convert these values to register specific values */
- if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)
- cfg->com_svs_mode_clk_sel = 1;
- else
- cfg->com_svs_mode_clk_sel = 2;
-
- cfg->com_hsclk_sel = (0x20 | pd.hsclk_divsel);
- cfg->com_pll_cctrl_mode0 = cctrl;
- cfg->com_pll_rctrl_mode0 = rctrl;
- cfg->com_cp_ctrl_mode0 = cpctrl;
- cfg->com_dec_start_mode0 = dec_start;
- cfg->com_div_frac_start1_mode0 = (frac_start & 0xff);
- cfg->com_div_frac_start2_mode0 = ((frac_start & 0xff00) >> 8);
- cfg->com_div_frac_start3_mode0 = ((frac_start & 0xf0000) >> 16);
- cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xff);
- cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xf00) >> 8);
- cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xff);
- cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xff00) >> 8);
- cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
- cfg->com_lock_cmp_en = 0x0;
- cfg->com_core_clk_en = 0x2c;
- cfg->com_coreclk_div = HDMI_CORECLK_DIV;
- cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
- cfg->com_vco_tune_ctrl = 0x0;
-
- cfg->tx_lx_lane_mode[0] =
- cfg->tx_lx_lane_mode[2] = 0x43;
-
- cfg->tx_lx_hp_pd_enables[0] =
- cfg->tx_lx_hp_pd_enables[1] =
- cfg->tx_lx_hp_pd_enables[2] = 0x0c;
- cfg->tx_lx_hp_pd_enables[3] = 0x3;
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)
- cfg->tx_lx_tx_band[i] = pd.tx_band_sel + 4;
-
- if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
- cfg->tx_lx_tx_drv_lvl[0] =
- cfg->tx_lx_tx_drv_lvl[1] =
- cfg->tx_lx_tx_drv_lvl[2] = 0x25;
- cfg->tx_lx_tx_drv_lvl[3] = 0x22;
-
- cfg->tx_lx_tx_emp_post1_lvl[0] =
- cfg->tx_lx_tx_emp_post1_lvl[1] =
- cfg->tx_lx_tx_emp_post1_lvl[2] = 0x23;
- cfg->tx_lx_tx_emp_post1_lvl[3] = 0x27;
-
- cfg->tx_lx_vmode_ctrl1[0] =
- cfg->tx_lx_vmode_ctrl1[1] =
- cfg->tx_lx_vmode_ctrl1[2] =
- cfg->tx_lx_vmode_ctrl1[3] = 0x00;
-
- cfg->tx_lx_vmode_ctrl2[0] =
- cfg->tx_lx_vmode_ctrl2[1] =
- cfg->tx_lx_vmode_ctrl2[2] = 0x0D;
-
- cfg->tx_lx_vmode_ctrl2[3] = 0x00;
- } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- cfg->tx_lx_tx_drv_lvl[i] = 0x25;
- cfg->tx_lx_tx_emp_post1_lvl[i] = 0x23;
- cfg->tx_lx_vmode_ctrl1[i] = 0x00;
- }
-
- cfg->tx_lx_vmode_ctrl2[0] =
- cfg->tx_lx_vmode_ctrl2[1] =
- cfg->tx_lx_vmode_ctrl2[2] = 0x0D;
- cfg->tx_lx_vmode_ctrl2[3] = 0x00;
- } else {
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- cfg->tx_lx_tx_drv_lvl[i] = 0x20;
- cfg->tx_lx_tx_emp_post1_lvl[i] = 0x20;
- cfg->tx_lx_vmode_ctrl1[i] = 0x00;
- cfg->tx_lx_vmode_ctrl2[i] = 0x0E;
- }
- }
-
- DBG("com_svs_mode_clk_sel = 0x%x", cfg->com_svs_mode_clk_sel);
- DBG("com_hsclk_sel = 0x%x", cfg->com_hsclk_sel);
- DBG("com_lock_cmp_en = 0x%x", cfg->com_lock_cmp_en);
- DBG("com_pll_cctrl_mode0 = 0x%x", cfg->com_pll_cctrl_mode0);
- DBG("com_pll_rctrl_mode0 = 0x%x", cfg->com_pll_rctrl_mode0);
- DBG("com_cp_ctrl_mode0 = 0x%x", cfg->com_cp_ctrl_mode0);
- DBG("com_dec_start_mode0 = 0x%x", cfg->com_dec_start_mode0);
- DBG("com_div_frac_start1_mode0 = 0x%x", cfg->com_div_frac_start1_mode0);
- DBG("com_div_frac_start2_mode0 = 0x%x", cfg->com_div_frac_start2_mode0);
- DBG("com_div_frac_start3_mode0 = 0x%x", cfg->com_div_frac_start3_mode0);
- DBG("com_integloop_gain0_mode0 = 0x%x", cfg->com_integloop_gain0_mode0);
- DBG("com_integloop_gain1_mode0 = 0x%x", cfg->com_integloop_gain1_mode0);
- DBG("com_lock_cmp1_mode0 = 0x%x", cfg->com_lock_cmp1_mode0);
- DBG("com_lock_cmp2_mode0 = 0x%x", cfg->com_lock_cmp2_mode0);
- DBG("com_lock_cmp3_mode0 = 0x%x", cfg->com_lock_cmp3_mode0);
- DBG("com_core_clk_en = 0x%x", cfg->com_core_clk_en);
- DBG("com_coreclk_div = 0x%x", cfg->com_coreclk_div);
- DBG("phy_mode = 0x%x", cfg->phy_mode);
-
- DBG("tx_l0_lane_mode = 0x%x", cfg->tx_lx_lane_mode[0]);
- DBG("tx_l2_lane_mode = 0x%x", cfg->tx_lx_lane_mode[2]);
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- DBG("tx_l%d_tx_band = 0x%x", i, cfg->tx_lx_tx_band[i]);
- DBG("tx_l%d_tx_drv_lvl = 0x%x", i, cfg->tx_lx_tx_drv_lvl[i]);
- DBG("tx_l%d_tx_emp_post1_lvl = 0x%x", i,
- cfg->tx_lx_tx_emp_post1_lvl[i]);
- DBG("tx_l%d_vmode_ctrl1 = 0x%x", i, cfg->tx_lx_vmode_ctrl1[i]);
- DBG("tx_l%d_vmode_ctrl2 = 0x%x", i, cfg->tx_lx_vmode_ctrl2[i]);
- }
-
- return 0;
-}
-
-static int hdmi_8996_pll_set_clk_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
- struct hdmi_8996_phy_pll_reg_cfg cfg;
- int i, ret;
-
- memset(&cfg, 0x00, sizeof(cfg));
-
- ret = pll_calculate(rate, parent_rate, &cfg);
- if (ret) {
- DRM_ERROR("PLL calculation failed\n");
- return ret;
- }
-
- /* Initially shut down PHY */
- DBG("Disabling PHY");
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x0);
- udelay(500);
-
- /* Power up sequence */
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_CTRL, 0x04);
-
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x1);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_RESETSM_CNTRL, 0x20);
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_TX0_TX1_LANE_CTL, 0x0F);
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_TX2_TX3_LANE_CTL, 0x0F);
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_CLKBUF_ENABLE,
- 0x03);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_TX_BAND,
- cfg.tx_lx_tx_band[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_RESET_TSYNC_EN,
- 0x03);
- }
-
- hdmi_tx_chan_write(pll, 0, REG_HDMI_PHY_QSERDES_TX_LX_LANE_MODE,
- cfg.tx_lx_lane_mode[0]);
- hdmi_tx_chan_write(pll, 2, REG_HDMI_PHY_QSERDES_TX_LX_LANE_MODE,
- cfg.tx_lx_lane_mode[2]);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYSCLK_EN_SEL, 0x37);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYS_CLK_CTRL, 0x02);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CLK_ENABLE1, 0x0E);
-
- /* Bypass VCO calibration */
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SVS_MODE_CLK_SEL,
- cfg.com_svs_mode_clk_sel);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_TRIM, 0x0F);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_IVCO, 0x0F);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_VCO_TUNE_CTRL,
- cfg.com_vco_tune_ctrl);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_CTRL, 0x06);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CLK_SELECT, 0x30);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_HSCLK_SEL,
- cfg.com_hsclk_sel);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP_EN,
- cfg.com_lock_cmp_en);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_CCTRL_MODE0,
- cfg.com_pll_cctrl_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_RCTRL_MODE0,
- cfg.com_pll_rctrl_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CP_CTRL_MODE0,
- cfg.com_cp_ctrl_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DEC_START_MODE0,
- cfg.com_dec_start_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START1_MODE0,
- cfg.com_div_frac_start1_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START2_MODE0,
- cfg.com_div_frac_start2_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START3_MODE0,
- cfg.com_div_frac_start3_mode0);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_INTEGLOOP_GAIN0_MODE0,
- cfg.com_integloop_gain0_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_INTEGLOOP_GAIN1_MODE0,
- cfg.com_integloop_gain1_mode0);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP1_MODE0,
- cfg.com_lock_cmp1_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP2_MODE0,
- cfg.com_lock_cmp2_mode0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP3_MODE0,
- cfg.com_lock_cmp3_mode0);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_VCO_TUNE_MAP, 0x00);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CORE_CLK_EN,
- cfg.com_core_clk_en);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CORECLK_DIV,
- cfg.com_coreclk_div);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CMN_CONFIG, 0x02);
-
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_RESCODE_DIV_NUM, 0x15);
-
- /* TX lanes setup (TX 0/1/2/3) */
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_TX_DRV_LVL,
- cfg.tx_lx_tx_drv_lvl[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_TX_EMP_POST1_LVL,
- cfg.tx_lx_tx_emp_post1_lvl[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_VMODE_CTRL1,
- cfg.tx_lx_vmode_ctrl1[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_VMODE_CTRL2,
- cfg.tx_lx_vmode_ctrl2[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_TX_DRV_LVL_OFFSET,
- 0x00);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_RES_CODE_LANE_OFFSET,
- 0x00);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_TRAN_DRVR_EMP_EN,
- 0x03);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_PARRATE_REC_DETECT_IDLE_EN,
- 0x40);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_HP_PD_ENABLES,
- cfg.tx_lx_hp_pd_enables[i]);
- }
-
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_MODE, cfg.phy_mode);
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x1F);
-
- /*
- * Ensure that vco configuration gets flushed to hardware before
- * enabling the PLL
- */
- wmb();
-
- return 0;
-}
-
-static int hdmi_8996_phy_ready_status(struct hdmi_phy *phy)
-{
- u32 nb_tries = HDMI_PLL_POLL_MAX_READS;
- unsigned long timeout = HDMI_PLL_POLL_TIMEOUT_US;
- u32 status;
- int phy_ready = 0;
-
- DBG("Waiting for PHY ready");
-
- while (nb_tries--) {
- status = hdmi_phy_read(phy, REG_HDMI_8996_PHY_STATUS);
- phy_ready = status & BIT(0);
-
- if (phy_ready)
- break;
-
- udelay(timeout);
- }
-
- DBG("PHY is %sready", phy_ready ? "" : "*not* ");
-
- return phy_ready;
-}
-
-static int hdmi_8996_pll_lock_status(struct hdmi_pll_8996 *pll)
-{
- u32 status;
- int nb_tries = HDMI_PLL_POLL_MAX_READS;
- unsigned long timeout = HDMI_PLL_POLL_TIMEOUT_US;
- int pll_locked = 0;
-
- DBG("Waiting for PLL lock");
-
- while (nb_tries--) {
- status = hdmi_pll_read(pll,
- REG_HDMI_PHY_QSERDES_COM_C_READY_STATUS);
- pll_locked = status & BIT(0);
-
- if (pll_locked)
- break;
-
- udelay(timeout);
- }
-
- DBG("HDMI PLL is %slocked", pll_locked ? "" : "*not* ");
-
- return pll_locked;
-}
-
-static int hdmi_8996_pll_prepare(struct clk_hw *hw)
-{
- struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
- int i, ret = 0;
-
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x1);
- udelay(100);
-
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x19);
- udelay(100);
-
- ret = hdmi_8996_pll_lock_status(pll);
- if (!ret)
- return ret;
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_PHY_QSERDES_TX_LX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
- 0x6F);
-
- /* Disable SSC */
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_PER1, 0x0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_PER2, 0x0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_STEP_SIZE1, 0x0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_STEP_SIZE2, 0x0);
- hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_EN_CENTER, 0x2);
-
- ret = hdmi_8996_phy_ready_status(phy);
- if (!ret)
- return ret;
-
- /* Restart the retiming buffer */
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x18);
- udelay(1);
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x19);
-
- return 0;
-}
-
-static int hdmi_8996_pll_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
-{
- req->rate = clamp_t(unsigned long, req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ);
-
- return 0;
-}
-
-static unsigned long hdmi_8996_pll_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);
- u64 fdata;
- u32 cmp1, cmp2, cmp3, pll_cmp;
-
- cmp1 = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP1_MODE0);
- cmp2 = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP2_MODE0);
- cmp3 = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP3_MODE0);
-
- pll_cmp = cmp1 | (cmp2 << 8) | (cmp3 << 16);
-
- fdata = pll_cmp_to_fdata(pll_cmp + 1, parent_rate);
-
- do_div(fdata, 10);
-
- return fdata;
-}
-
-static void hdmi_8996_pll_unprepare(struct clk_hw *hw)
-{
- struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
-
- hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x6);
- usleep_range(100, 150);
-}
-
-static int hdmi_8996_pll_is_enabled(struct clk_hw *hw)
-{
- struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);
- u32 status;
- int pll_locked;
-
- status = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_C_READY_STATUS);
- pll_locked = status & BIT(0);
-
- return pll_locked;
-}
-
-static const struct clk_ops hdmi_8996_pll_ops = {
- .set_rate = hdmi_8996_pll_set_clk_rate,
- .determine_rate = hdmi_8996_pll_determine_rate,
- .recalc_rate = hdmi_8996_pll_recalc_rate,
- .prepare = hdmi_8996_pll_prepare,
- .unprepare = hdmi_8996_pll_unprepare,
- .is_enabled = hdmi_8996_pll_is_enabled,
-};
-
-static const struct clk_init_data pll_init = {
- .name = "hdmipll",
- .ops = &hdmi_8996_pll_ops,
- .parent_data = (const struct clk_parent_data[]){
- { .fw_name = "xo", .name = "xo_board" },
- },
- .num_parents = 1,
- .flags = CLK_IGNORE_UNUSED,
-};
-
-int msm_hdmi_pll_8996_init(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct hdmi_pll_8996 *pll;
- int i, ret;
-
- pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
- if (!pll)
- return -ENOMEM;
-
- pll->pdev = pdev;
-
- pll->mmio_qserdes_com = msm_ioremap(pdev, "hdmi_pll");
- if (IS_ERR(pll->mmio_qserdes_com)) {
- DRM_DEV_ERROR(dev, "failed to map pll base\n");
- return -ENOMEM;
- }
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- char name[32];
-
- snprintf(name, sizeof(name), "hdmi_tx_l%d", i);
-
- pll->mmio_qserdes_tx[i] = msm_ioremap(pdev, name);
- if (IS_ERR(pll->mmio_qserdes_tx[i])) {
- DRM_DEV_ERROR(dev, "failed to map pll base\n");
- return -ENOMEM;
- }
- }
- pll->clk_hw.init = &pll_init;
-
- ret = devm_clk_hw_register(dev, &pll->clk_hw);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register pll clock\n");
- return ret;
- }
-
- ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
- if (ret) {
- DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
- return ret;
- }
-
- return 0;
-}
-
-static const char * const hdmi_phy_8996_reg_names[] = {
- "vddio",
- "vcca",
-};
-
-static const char * const hdmi_phy_8996_clk_names[] = {
- "iface", "ref",
-};
-
-const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg = {
- .type = MSM_HDMI_PHY_8996,
- .reg_names = hdmi_phy_8996_reg_names,
- .num_regs = ARRAY_SIZE(hdmi_phy_8996_reg_names),
- .clk_names = hdmi_phy_8996_clk_names,
- .num_clks = ARRAY_SIZE(hdmi_phy_8996_clk_names),
-};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c
deleted file mode 100644
index a86ff3706369..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c
+++ /dev/null
@@ -1,765 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- * Copyright (c) 2024 Freebox SAS
- */
-
-#include <linux/clk-provider.h>
-#include <linux/delay.h>
-
-#include "hdmi.h"
-
-#define HDMI_VCO_MAX_FREQ 12000000000UL
-#define HDMI_VCO_MIN_FREQ 8000000000UL
-
-#define HDMI_PCLK_MAX_FREQ 600000000
-#define HDMI_PCLK_MIN_FREQ 25000000
-
-#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL
-#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL
-#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL
-#define HDMI_CORECLK_DIV 5
-#define HDMI_DEFAULT_REF_CLOCK 19200000
-#define HDMI_PLL_CMP_CNT 1024
-
-#define HDMI_PLL_POLL_MAX_READS 100
-#define HDMI_PLL_POLL_TIMEOUT_US 150
-
-#define HDMI_NUM_TX_CHANNEL 4
-
-struct hdmi_pll_8998 {
- struct platform_device *pdev;
- struct clk_hw clk_hw;
- unsigned long rate;
-
- /* pll mmio base */
- void __iomem *mmio_qserdes_com;
- /* tx channel base */
- void __iomem *mmio_qserdes_tx[HDMI_NUM_TX_CHANNEL];
-};
-
-#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8998, clk_hw)
-
-struct hdmi_8998_phy_pll_reg_cfg {
- u32 com_svs_mode_clk_sel;
- u32 com_hsclk_sel;
- u32 com_pll_cctrl_mode0;
- u32 com_pll_rctrl_mode0;
- u32 com_cp_ctrl_mode0;
- u32 com_dec_start_mode0;
- u32 com_div_frac_start1_mode0;
- u32 com_div_frac_start2_mode0;
- u32 com_div_frac_start3_mode0;
- u32 com_integloop_gain0_mode0;
- u32 com_integloop_gain1_mode0;
- u32 com_lock_cmp_en;
- u32 com_lock_cmp1_mode0;
- u32 com_lock_cmp2_mode0;
- u32 com_lock_cmp3_mode0;
- u32 com_core_clk_en;
- u32 com_coreclk_div_mode0;
-
- u32 tx_lx_tx_band[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_tx_drv_lvl[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_tx_emp_post1_lvl[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_pre_driver_1[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_pre_driver_2[HDMI_NUM_TX_CHANNEL];
- u32 tx_lx_res_code_offset[HDMI_NUM_TX_CHANNEL];
-
- u32 phy_mode;
-};
-
-struct hdmi_8998_post_divider {
- u64 vco_freq;
- int hsclk_divsel;
- int vco_ratio;
- int tx_band_sel;
- int half_rate_mode;
-};
-
-static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8998 *pll)
-{
- return platform_get_drvdata(pll->pdev);
-}
-
-static inline void hdmi_pll_write(struct hdmi_pll_8998 *pll, int offset,
- u32 data)
-{
- writel(data, pll->mmio_qserdes_com + offset);
-}
-
-static inline u32 hdmi_pll_read(struct hdmi_pll_8998 *pll, int offset)
-{
- return readl(pll->mmio_qserdes_com + offset);
-}
-
-static inline void hdmi_tx_chan_write(struct hdmi_pll_8998 *pll, int channel,
- int offset, int data)
-{
- writel(data, pll->mmio_qserdes_tx[channel] + offset);
-}
-
-static inline u32 pll_get_cpctrl(u64 frac_start, unsigned long ref_clk,
- bool gen_ssc)
-{
- if ((frac_start != 0) || gen_ssc)
- return 0x8;
-
- return 0x30;
-}
-
-static inline u32 pll_get_rctrl(u64 frac_start, bool gen_ssc)
-{
- if ((frac_start != 0) || gen_ssc)
- return 0x16;
-
- return 0x18;
-}
-
-static inline u32 pll_get_cctrl(u64 frac_start, bool gen_ssc)
-{
- if ((frac_start != 0) || gen_ssc)
- return 0x34;
-
- return 0x2;
-}
-
-static inline u32 pll_get_integloop_gain(u64 frac_start, u64 bclk, u32 ref_clk,
- bool gen_ssc)
-{
- int digclk_divsel = bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2;
- u64 base;
-
- if ((frac_start != 0) || gen_ssc)
- base = 0x3F;
- else
- base = 0xC4;
-
- base <<= (digclk_divsel == 2 ? 1 : 0);
-
- return base;
-}
-
-static inline u32 pll_get_pll_cmp(u64 fdata, unsigned long ref_clk)
-{
- u64 dividend = HDMI_PLL_CMP_CNT * fdata;
- u32 divisor = ref_clk * 10;
- u32 rem;
-
- rem = do_div(dividend, divisor);
- if (rem > (divisor >> 1))
- dividend++;
-
- return dividend - 1;
-}
-
-#define HDMI_REF_CLOCK_HZ ((u64)19200000)
-#define HDMI_MHZ_TO_HZ ((u64)1000000)
-static int pll_get_post_div(struct hdmi_8998_post_divider *pd, u64 bclk)
-{
- static const u32 ratio_list[] = {1, 2, 3, 4, 5, 6, 9, 10, 12, 15, 25};
- static const u32 band_list[] = {0, 1, 2, 3};
- u32 const sz_ratio = ARRAY_SIZE(ratio_list);
- u32 const sz_band = ARRAY_SIZE(band_list);
- u32 const cmp_cnt = 1024;
- u32 const th_min = 500, th_max = 1000;
- u32 half_rate_mode = 0;
- u32 list_elements;
- int optimal_index;
- u32 i, j, k;
- u32 found_hsclk_divsel = 0, found_vco_ratio;
- u32 found_tx_band_sel;
- u64 const min_freq = HDMI_VCO_MIN_FREQ, max_freq = HDMI_VCO_MAX_FREQ;
- u64 freq_list[ARRAY_SIZE(ratio_list) * ARRAY_SIZE(band_list)];
- u64 found_vco_freq;
- u64 freq_optimal;
-
-find_optimal_index:
- freq_optimal = max_freq;
- optimal_index = -1;
- list_elements = 0;
-
- for (i = 0; i < sz_ratio; i++) {
- for (j = 0; j < sz_band; j++) {
- u64 freq = div_u64(bclk, (1 << half_rate_mode));
-
- freq *= (ratio_list[i] * (1 << band_list[j]));
- freq_list[list_elements++] = freq;
- }
- }
-
- for (k = 0; k < ARRAY_SIZE(freq_list); k++) {
- u32 const clks_pll_div = 2, core_clk_div = 5;
- u32 const rng1 = 16, rng2 = 8;
- u32 th1, th2;
- u64 core_clk, rvar1, rem;
-
- core_clk = div_u64(freq_list[k],
- ratio_list[k / sz_band] * clks_pll_div *
- core_clk_div);
-
- rvar1 = HDMI_REF_CLOCK_HZ * rng1 * HDMI_MHZ_TO_HZ;
- rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem);
- if (rem > ((cmp_cnt * core_clk) >> 1))
- rvar1++;
- th1 = rvar1;
-
- rvar1 = HDMI_REF_CLOCK_HZ * rng2 * HDMI_MHZ_TO_HZ;
- rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem);
- if (rem > ((cmp_cnt * core_clk) >> 1))
- rvar1++;
- th2 = rvar1;
-
- if (freq_list[k] >= min_freq &&
- freq_list[k] <= max_freq) {
- if ((th1 >= th_min && th1 <= th_max) ||
- (th2 >= th_min && th2 <= th_max)) {
- if (freq_list[k] <= freq_optimal) {
- freq_optimal = freq_list[k];
- optimal_index = k;
- }
- }
- }
- }
-
- if (optimal_index == -1) {
- if (!half_rate_mode) {
- half_rate_mode = 1;
- goto find_optimal_index;
- } else {
- return -EINVAL;
- }
- } else {
- found_vco_ratio = ratio_list[optimal_index / sz_band];
- found_tx_band_sel = band_list[optimal_index % sz_band];
- found_vco_freq = freq_optimal;
- }
-
- switch (found_vco_ratio) {
- case 1:
- found_hsclk_divsel = 15;
- break;
- case 2:
- found_hsclk_divsel = 0;
- break;
- case 3:
- found_hsclk_divsel = 4;
- break;
- case 4:
- found_hsclk_divsel = 8;
- break;
- case 5:
- found_hsclk_divsel = 12;
- break;
- case 6:
- found_hsclk_divsel = 1;
- break;
- case 9:
- found_hsclk_divsel = 5;
- break;
- case 10:
- found_hsclk_divsel = 2;
- break;
- case 12:
- found_hsclk_divsel = 9;
- break;
- case 15:
- found_hsclk_divsel = 13;
- break;
- case 25:
- found_hsclk_divsel = 14;
- break;
- }
-
- pd->vco_freq = found_vco_freq;
- pd->tx_band_sel = found_tx_band_sel;
- pd->vco_ratio = found_vco_ratio;
- pd->hsclk_divsel = found_hsclk_divsel;
-
- return 0;
-}
-
-static int pll_calculate(unsigned long pix_clk, unsigned long ref_clk,
- struct hdmi_8998_phy_pll_reg_cfg *cfg)
-{
- struct hdmi_8998_post_divider pd;
- u64 bclk;
- u64 dec_start;
- u64 frac_start;
- u64 fdata;
- u32 pll_divisor;
- u32 rem;
- u32 cpctrl;
- u32 rctrl;
- u32 cctrl;
- u32 integloop_gain;
- u32 pll_cmp;
- int i, ret;
-
- /* bit clk = 10 * pix_clk */
- bclk = ((u64)pix_clk) * 10;
-
- ret = pll_get_post_div(&pd, bclk);
- if (ret)
- return ret;
-
- dec_start = pd.vco_freq;
- pll_divisor = 4 * ref_clk;
- do_div(dec_start, pll_divisor);
-
- frac_start = pd.vco_freq * (1 << 20);
-
- rem = do_div(frac_start, pll_divisor);
- frac_start -= dec_start * (1 << 20);
- if (rem > (pll_divisor >> 1))
- frac_start++;
-
- cpctrl = pll_get_cpctrl(frac_start, ref_clk, false);
- rctrl = pll_get_rctrl(frac_start, false);
- cctrl = pll_get_cctrl(frac_start, false);
- integloop_gain = pll_get_integloop_gain(frac_start, bclk,
- ref_clk, false);
-
- fdata = pd.vco_freq;
- do_div(fdata, pd.vco_ratio);
-
- pll_cmp = pll_get_pll_cmp(fdata, ref_clk);
-
- /* Convert these values to register specific values */
- if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)
- cfg->com_svs_mode_clk_sel = 1;
- else
- cfg->com_svs_mode_clk_sel = 2;
-
- cfg->com_hsclk_sel = (0x20 | pd.hsclk_divsel);
- cfg->com_pll_cctrl_mode0 = cctrl;
- cfg->com_pll_rctrl_mode0 = rctrl;
- cfg->com_cp_ctrl_mode0 = cpctrl;
- cfg->com_dec_start_mode0 = dec_start;
- cfg->com_div_frac_start1_mode0 = (frac_start & 0xff);
- cfg->com_div_frac_start2_mode0 = ((frac_start & 0xff00) >> 8);
- cfg->com_div_frac_start3_mode0 = ((frac_start & 0xf0000) >> 16);
- cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xff);
- cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xf00) >> 8);
- cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xff);
- cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xff00) >> 8);
- cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
- cfg->com_lock_cmp_en = 0x0;
- cfg->com_core_clk_en = 0x2c;
- cfg->com_coreclk_div_mode0 = HDMI_CORECLK_DIV;
- cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x5 : 0x4;
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)
- cfg->tx_lx_tx_band[i] = pd.tx_band_sel;
-
- if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
- cfg->tx_lx_tx_drv_lvl[0] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[1] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[2] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[3] = 0x0f;
- cfg->tx_lx_tx_emp_post1_lvl[0] = 0x03;
- cfg->tx_lx_tx_emp_post1_lvl[1] = 0x02;
- cfg->tx_lx_tx_emp_post1_lvl[2] = 0x03;
- cfg->tx_lx_tx_emp_post1_lvl[3] = 0x00;
- cfg->tx_lx_pre_driver_1[0] = 0x00;
- cfg->tx_lx_pre_driver_1[1] = 0x00;
- cfg->tx_lx_pre_driver_1[2] = 0x00;
- cfg->tx_lx_pre_driver_1[3] = 0x00;
- cfg->tx_lx_pre_driver_2[0] = 0x1C;
- cfg->tx_lx_pre_driver_2[1] = 0x1C;
- cfg->tx_lx_pre_driver_2[2] = 0x1C;
- cfg->tx_lx_pre_driver_2[3] = 0x00;
- cfg->tx_lx_res_code_offset[0] = 0x03;
- cfg->tx_lx_res_code_offset[1] = 0x00;
- cfg->tx_lx_res_code_offset[2] = 0x00;
- cfg->tx_lx_res_code_offset[3] = 0x03;
- } else if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
- cfg->tx_lx_tx_drv_lvl[0] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[1] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[2] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[3] = 0x0f;
- cfg->tx_lx_tx_emp_post1_lvl[0] = 0x03;
- cfg->tx_lx_tx_emp_post1_lvl[1] = 0x03;
- cfg->tx_lx_tx_emp_post1_lvl[2] = 0x03;
- cfg->tx_lx_tx_emp_post1_lvl[3] = 0x00;
- cfg->tx_lx_pre_driver_1[0] = 0x00;
- cfg->tx_lx_pre_driver_1[1] = 0x00;
- cfg->tx_lx_pre_driver_1[2] = 0x00;
- cfg->tx_lx_pre_driver_1[3] = 0x00;
- cfg->tx_lx_pre_driver_2[0] = 0x16;
- cfg->tx_lx_pre_driver_2[1] = 0x16;
- cfg->tx_lx_pre_driver_2[2] = 0x16;
- cfg->tx_lx_pre_driver_2[3] = 0x18;
- cfg->tx_lx_res_code_offset[0] = 0x03;
- cfg->tx_lx_res_code_offset[1] = 0x00;
- cfg->tx_lx_res_code_offset[2] = 0x00;
- cfg->tx_lx_res_code_offset[3] = 0x00;
- } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
- cfg->tx_lx_tx_drv_lvl[0] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[1] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[2] = 0x0f;
- cfg->tx_lx_tx_drv_lvl[3] = 0x0f;
- cfg->tx_lx_tx_emp_post1_lvl[0] = 0x05;
- cfg->tx_lx_tx_emp_post1_lvl[1] = 0x05;
- cfg->tx_lx_tx_emp_post1_lvl[2] = 0x05;
- cfg->tx_lx_tx_emp_post1_lvl[3] = 0x00;
- cfg->tx_lx_pre_driver_1[0] = 0x00;
- cfg->tx_lx_pre_driver_1[1] = 0x00;
- cfg->tx_lx_pre_driver_1[2] = 0x00;
- cfg->tx_lx_pre_driver_1[3] = 0x00;
- cfg->tx_lx_pre_driver_2[0] = 0x0E;
- cfg->tx_lx_pre_driver_2[1] = 0x0E;
- cfg->tx_lx_pre_driver_2[2] = 0x0E;
- cfg->tx_lx_pre_driver_2[3] = 0x0E;
- cfg->tx_lx_res_code_offset[0] = 0x00;
- cfg->tx_lx_res_code_offset[1] = 0x00;
- cfg->tx_lx_res_code_offset[2] = 0x00;
- cfg->tx_lx_res_code_offset[3] = 0x00;
- } else {
- cfg->tx_lx_tx_drv_lvl[0] = 0x01;
- cfg->tx_lx_tx_drv_lvl[1] = 0x01;
- cfg->tx_lx_tx_drv_lvl[2] = 0x01;
- cfg->tx_lx_tx_drv_lvl[3] = 0x00;
- cfg->tx_lx_tx_emp_post1_lvl[0] = 0x00;
- cfg->tx_lx_tx_emp_post1_lvl[1] = 0x00;
- cfg->tx_lx_tx_emp_post1_lvl[2] = 0x00;
- cfg->tx_lx_tx_emp_post1_lvl[3] = 0x00;
- cfg->tx_lx_pre_driver_1[0] = 0x00;
- cfg->tx_lx_pre_driver_1[1] = 0x00;
- cfg->tx_lx_pre_driver_1[2] = 0x00;
- cfg->tx_lx_pre_driver_1[3] = 0x00;
- cfg->tx_lx_pre_driver_2[0] = 0x16;
- cfg->tx_lx_pre_driver_2[1] = 0x16;
- cfg->tx_lx_pre_driver_2[2] = 0x16;
- cfg->tx_lx_pre_driver_2[3] = 0x18;
- cfg->tx_lx_res_code_offset[0] = 0x00;
- cfg->tx_lx_res_code_offset[1] = 0x00;
- cfg->tx_lx_res_code_offset[2] = 0x00;
- cfg->tx_lx_res_code_offset[3] = 0x00;
- }
-
- return 0;
-}
-
-static int hdmi_8998_pll_set_clk_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct hdmi_pll_8998 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
- struct hdmi_8998_phy_pll_reg_cfg cfg = {};
- int i, ret;
-
- ret = pll_calculate(rate, parent_rate, &cfg);
- if (ret) {
- DRM_ERROR("PLL calculation failed\n");
- return ret;
- }
-
- /* Initially shut down PHY */
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_PD_CTL, 0x0);
- udelay(500);
-
- /* Power up sequence */
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_PD_CTL, 0x1);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_RESETSM_CNTRL, 0x20);
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_CMN_CTRL, 0x6);
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND,
- cfg.tx_lx_tx_band[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE,
- 0x1);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_LANE_MODE,
- 0x20);
- }
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SYSCLK_BUF_ENABLE, 0x02);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x0B);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SYSCLK_EN_SEL, 0x37);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SYS_CLK_CTRL, 0x02);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CLK_ENABLE1, 0x0E);
-
- /* Bypass VCO calibration */
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SVS_MODE_CLK_SEL,
- cfg.com_svs_mode_clk_sel);
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_PLL_IVCO, 0x07);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_VCO_TUNE_CTRL, 0x00);
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CLK_SEL, 0x30);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_HSCLK_SEL,
- cfg.com_hsclk_sel);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP_EN,
- cfg.com_lock_cmp_en);
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_PLL_CCTRL_MODE0,
- cfg.com_pll_cctrl_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_PLL_RCTRL_MODE0,
- cfg.com_pll_rctrl_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CP_CTRL_MODE0,
- cfg.com_cp_ctrl_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DEC_START_MODE0,
- cfg.com_dec_start_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DIV_FRAC_START1_MODE0,
- cfg.com_div_frac_start1_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DIV_FRAC_START2_MODE0,
- cfg.com_div_frac_start2_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DIV_FRAC_START3_MODE0,
- cfg.com_div_frac_start3_mode0);
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_INTEGLOOP_GAIN0_MODE0,
- cfg.com_integloop_gain0_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_INTEGLOOP_GAIN1_MODE0,
- cfg.com_integloop_gain1_mode0);
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP1_MODE0,
- cfg.com_lock_cmp1_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP2_MODE0,
- cfg.com_lock_cmp2_mode0);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP3_MODE0,
- cfg.com_lock_cmp3_mode0);
-
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_VCO_TUNE_MAP, 0x00);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CORE_CLK_EN,
- cfg.com_core_clk_en);
- hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CORECLK_DIV_MODE0,
- cfg.com_coreclk_div_mode0);
-
- /* TX lanes setup (TX 0/1/2/3) */
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_DRV_LVL,
- cfg.tx_lx_tx_drv_lvl[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_EMP_POST1_LVL,
- cfg.tx_lx_tx_emp_post1_lvl[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_PRE_DRIVER_1,
- cfg.tx_lx_pre_driver_1[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_PRE_DRIVER_2,
- cfg.tx_lx_pre_driver_2[i]);
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET,
- cfg.tx_lx_res_code_offset[i]);
- }
-
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_MODE, cfg.phy_mode);
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_LANE_CONFIG,
- 0x10);
- }
-
- /*
- * Ensure that vco configuration gets flushed to hardware before
- * enabling the PLL
- */
- wmb();
-
- pll->rate = rate;
-
- return 0;
-}
-
-static int hdmi_8998_phy_ready_status(struct hdmi_phy *phy)
-{
- u32 nb_tries = HDMI_PLL_POLL_MAX_READS;
- unsigned long timeout = HDMI_PLL_POLL_TIMEOUT_US;
- u32 status;
- int phy_ready = 0;
-
- while (nb_tries--) {
- status = hdmi_phy_read(phy, REG_HDMI_8998_PHY_STATUS);
- phy_ready = status & BIT(0);
-
- if (phy_ready)
- break;
-
- udelay(timeout);
- }
-
- return phy_ready;
-}
-
-static int hdmi_8998_pll_lock_status(struct hdmi_pll_8998 *pll)
-{
- u32 status;
- int nb_tries = HDMI_PLL_POLL_MAX_READS;
- unsigned long timeout = HDMI_PLL_POLL_TIMEOUT_US;
- int pll_locked = 0;
-
- while (nb_tries--) {
- status = hdmi_pll_read(pll,
- REG_HDMI_8998_PHY_QSERDES_COM_C_READY_STATUS);
- pll_locked = status & BIT(0);
-
- if (pll_locked)
- break;
-
- udelay(timeout);
- }
-
- return pll_locked;
-}
-
-static int hdmi_8998_pll_prepare(struct clk_hw *hw)
-{
- struct hdmi_pll_8998 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
- int i, ret = 0;
-
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x1);
- udelay(100);
-
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x59);
- udelay(100);
-
- ret = hdmi_8998_pll_lock_status(pll);
- if (!ret)
- return ret;
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- hdmi_tx_chan_write(pll, i,
- REG_HDMI_8998_PHY_TXn_LANE_CONFIG, 0x1F);
- }
-
- /* Ensure all registers are flushed to hardware */
- wmb();
-
- ret = hdmi_8998_phy_ready_status(phy);
- if (!ret)
- return ret;
-
- /* Restart the retiming buffer */
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x58);
- udelay(1);
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x59);
-
- /* Ensure all registers are flushed to hardware */
- wmb();
-
- return 0;
-}
-
-static int hdmi_8998_pll_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
-{
- req->rate = clamp_t(unsigned long, req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ);
-
- return 0;
-}
-
-static unsigned long hdmi_8998_pll_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct hdmi_pll_8998 *pll = hw_clk_to_pll(hw);
- return pll->rate;
-}
-
-static void hdmi_8998_pll_unprepare(struct clk_hw *hw)
-{
- struct hdmi_pll_8998 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
-
- hdmi_phy_write(phy, REG_HDMI_8998_PHY_PD_CTL, 0);
- usleep_range(100, 150);
-}
-
-static int hdmi_8998_pll_is_enabled(struct clk_hw *hw)
-{
- struct hdmi_pll_8998 *pll = hw_clk_to_pll(hw);
- u32 status;
- int pll_locked;
-
- status = hdmi_pll_read(pll, REG_HDMI_8998_PHY_QSERDES_COM_C_READY_STATUS);
- pll_locked = status & BIT(0);
-
- return pll_locked;
-}
-
-static const struct clk_ops hdmi_8998_pll_ops = {
- .set_rate = hdmi_8998_pll_set_clk_rate,
- .determine_rate = hdmi_8998_pll_determine_rate,
- .recalc_rate = hdmi_8998_pll_recalc_rate,
- .prepare = hdmi_8998_pll_prepare,
- .unprepare = hdmi_8998_pll_unprepare,
- .is_enabled = hdmi_8998_pll_is_enabled,
-};
-
-static const struct clk_init_data pll_init = {
- .name = "hdmipll",
- .ops = &hdmi_8998_pll_ops,
- .parent_data = (const struct clk_parent_data[]){
- { .fw_name = "xo", .name = "xo_board" },
- },
- .num_parents = 1,
- .flags = CLK_IGNORE_UNUSED,
-};
-
-int msm_hdmi_pll_8998_init(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct hdmi_pll_8998 *pll;
- int ret, i;
-
- pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
- if (!pll)
- return -ENOMEM;
-
- pll->pdev = pdev;
-
- pll->mmio_qserdes_com = msm_ioremap(pdev, "hdmi_pll");
- if (IS_ERR(pll->mmio_qserdes_com)) {
- DRM_DEV_ERROR(dev, "failed to map pll base\n");
- return -ENOMEM;
- }
-
- for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
- char name[32];
-
- snprintf(name, sizeof(name), "hdmi_tx_l%d", i);
-
- pll->mmio_qserdes_tx[i] = msm_ioremap(pdev, name);
- if (IS_ERR(pll->mmio_qserdes_tx[i])) {
- DRM_DEV_ERROR(dev, "failed to map pll base\n");
- return -ENOMEM;
- }
- }
- pll->clk_hw.init = &pll_init;
-
- ret = devm_clk_hw_register(dev, &pll->clk_hw);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register pll clock\n");
- return ret;
- }
-
- ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static const char * const hdmi_phy_8998_reg_names[] = {
- "vddio",
- "vcca",
-};
-
-static const char * const hdmi_phy_8998_clk_names[] = {
- "iface", "ref", "xo",
-};
-
-const struct hdmi_phy_cfg msm_hdmi_phy_8998_cfg = {
- .type = MSM_HDMI_PHY_8998,
- .reg_names = hdmi_phy_8998_reg_names,
- .num_regs = ARRAY_SIZE(hdmi_phy_8998_reg_names),
- .clk_names = hdmi_phy_8998_clk_names,
- .num_clks = ARRAY_SIZE(hdmi_phy_8998_clk_names),
-};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
deleted file mode 100644
index 1d97640d8c24..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
+++ /dev/null
@@ -1,141 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- */
-
-#include <linux/delay.h>
-
-#include "hdmi.h"
-
-static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy,
- unsigned long int pixclock)
-{
- /* De-serializer delay D/C for non-lbk mode: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG0,
- HDMI_8x60_PHY_REG0_DESER_DEL_CTRL(3));
-
- if (pixclock == 27000000) {
- /* video_format == HDMI_VFRMT_720x480p60_16_9 */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG1,
- HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) |
- HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(3));
- } else {
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG1,
- HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) |
- HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(4));
- }
-
- /* No matter what, start from the power down mode: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_PD_PWRGEN |
- HDMI_8x60_PHY_REG2_PD_PLL |
- HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
- HDMI_8x60_PHY_REG2_PD_DESER);
-
- /* Turn PowerGen on: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_PD_PLL |
- HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
- HDMI_8x60_PHY_REG2_PD_DESER);
-
- /* Turn PLL power on: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
- HDMI_8x60_PHY_REG2_PD_DESER);
-
- /* Write to HIGH after PLL power down de-assert: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG3,
- HDMI_8x60_PHY_REG3_PLL_ENABLE);
-
- /* ASIC power on; PHY REG9 = 0 */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG9, 0);
-
- /* Enable PLL lock detect, PLL lock det will go high after lock
- * Enable the re-time logic
- */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG12,
- HDMI_8x60_PHY_REG12_RETIMING_EN |
- HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN);
-
- /* Drivers are on: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_PD_DESER);
-
- /* If the RX detector is needed: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
- HDMI_8x60_PHY_REG2_PD_DESER);
-
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG4, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG5, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG6, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG7, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG8, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG9, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG10, 0);
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG11, 0);
-
- /* If we want to use lock enable based on counting: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG12,
- HDMI_8x60_PHY_REG12_RETIMING_EN |
- HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN |
- HDMI_8x60_PHY_REG12_FORCE_LOCK);
-}
-
-static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy)
-{
- /* Assert RESET PHY from controller */
- hdmi_phy_write(phy, REG_HDMI_PHY_CTRL,
- HDMI_PHY_CTRL_SW_RESET);
- udelay(10);
- /* De-assert RESET PHY from controller */
- hdmi_phy_write(phy, REG_HDMI_PHY_CTRL, 0);
- /* Turn off Driver */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
- HDMI_8x60_PHY_REG2_PD_DESER);
- udelay(10);
- /* Disable PLL */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG3, 0);
- /* Power down PHY, but keep RX-sense: */
- hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2,
- HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
- HDMI_8x60_PHY_REG2_PD_PWRGEN |
- HDMI_8x60_PHY_REG2_PD_PLL |
- HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
- HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
- HDMI_8x60_PHY_REG2_PD_DESER);
-}
-
-static const char * const hdmi_phy_8x60_reg_names[] = {
- "core-vdda",
-};
-
-static const char * const hdmi_phy_8x60_clk_names[] = {
- "slave_iface",
-};
-
-const struct hdmi_phy_cfg msm_hdmi_phy_8x60_cfg = {
- .type = MSM_HDMI_PHY_8x60,
- .powerup = hdmi_phy_8x60_powerup,
- .powerdown = hdmi_phy_8x60_powerdown,
- .reg_names = hdmi_phy_8x60_reg_names,
- .num_regs = ARRAY_SIZE(hdmi_phy_8x60_reg_names),
- .clk_names = hdmi_phy_8x60_clk_names,
- .num_clks = ARRAY_SIZE(hdmi_phy_8x60_clk_names),
-};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
deleted file mode 100644
index a2a6940e195a..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- */
-
-#include "hdmi.h"
-
-static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy,
- unsigned long int pixclock)
-{
- hdmi_phy_write(phy, REG_HDMI_8x74_ANA_CFG0, 0x1b);
- hdmi_phy_write(phy, REG_HDMI_8x74_ANA_CFG1, 0xf2);
- hdmi_phy_write(phy, REG_HDMI_8x74_BIST_CFG0, 0x0);
- hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN0, 0x0);
- hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN1, 0x0);
- hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN2, 0x0);
- hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN3, 0x0);
- hdmi_phy_write(phy, REG_HDMI_8x74_PD_CTRL1, 0x20);
-}
-
-static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy)
-{
- hdmi_phy_write(phy, REG_HDMI_8x74_PD_CTRL0, 0x7f);
-}
-
-static const char * const hdmi_phy_8x74_reg_names[] = {
- "core-vdda",
- "vddio",
-};
-
-static const char * const hdmi_phy_8x74_clk_names[] = {
- "iface", "alt_iface"
-};
-
-const struct hdmi_phy_cfg msm_hdmi_phy_8x74_cfg = {
- .type = MSM_HDMI_PHY_8x74,
- .powerup = hdmi_phy_8x74_powerup,
- .powerdown = hdmi_phy_8x74_powerdown,
- .reg_names = hdmi_phy_8x74_reg_names,
- .num_regs = ARRAY_SIZE(hdmi_phy_8x74_reg_names),
- .clk_names = hdmi_phy_8x74_clk_names,
- .num_clks = ARRAY_SIZE(hdmi_phy_8x74_clk_names),
-};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
deleted file mode 100644
index 6ba6bbdb7e05..000000000000
--- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
+++ /dev/null
@@ -1,460 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- */
-
-#include <linux/clk-provider.h>
-#include <linux/delay.h>
-
-#include "hdmi.h"
-
-struct hdmi_pll_8960 {
- struct platform_device *pdev;
- struct clk_hw clk_hw;
- void __iomem *mmio;
-
- unsigned long pixclk;
-};
-
-#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8960, clk_hw)
-
-/*
- * HDMI PLL:
- *
- * To get the parent clock setup properly, we need to plug in hdmi pll
- * configuration into common-clock-framework.
- */
-
-struct pll_rate {
- unsigned long rate;
- int num_reg;
- struct {
- u32 val;
- u32 reg;
- } conf[32];
-};
-
-/* NOTE: keep sorted highest freq to lowest: */
-static const struct pll_rate freqtbl[] = {
- { 154000000, 14, {
- { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- }
- },
- /* 1080p60/1080p50 case */
- { 148500000, 27, {
- { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
- { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
- { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
- { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
- { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
- { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
- { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
- { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
- { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
- }
- },
- { 108000000, 13, {
- { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- }
- },
- /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */
- { 74250000, 8, {
- { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
- { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- }
- },
- { 74176000, 14, {
- { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- }
- },
- { 65000000, 14, {
- { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- }
- },
- /* 480p60/480i60 */
- { 27030000, 18, {
- { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
- { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
- { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
- }
- },
- /* 576p50/576i50 */
- { 27000000, 27, {
- { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
- { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
- { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
- { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
- { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
- { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
- { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
- { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
- { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
- }
- },
- /* 640x480p60 */
- { 25200000, 27, {
- { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
- { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
- { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
- { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
- { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
- { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
- { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
- { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
- { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
- { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
- { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
- { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
- { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
- { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
- { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
- { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
- { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
- { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
- { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
- { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
- { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
- { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
- }
- },
-};
-
-static inline void pll_write(struct hdmi_pll_8960 *pll, u32 reg, u32 data)
-{
- writel(data, pll->mmio + reg);
-}
-
-static inline u32 pll_read(struct hdmi_pll_8960 *pll, u32 reg)
-{
- return readl(pll->mmio + reg);
-}
-
-static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8960 *pll)
-{
- return platform_get_drvdata(pll->pdev);
-}
-
-static int hdmi_pll_enable(struct clk_hw *hw)
-{
- struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
- int timeout_count, pll_lock_retry = 10;
- unsigned int val;
-
- DBG("");
-
- /* Assert PLL S/W reset */
- pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
- pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
- pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a);
-
- /* Wait for a short time before de-asserting
- * to allow the hardware to complete its job.
- * This much of delay should be fine for hardware
- * to assert and de-assert.
- */
- udelay(10);
-
- /* De-assert PLL S/W reset */
- pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
-
- val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
- val |= HDMI_8960_PHY_REG12_SW_RESET;
- /* Assert PHY S/W reset */
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
- val &= ~HDMI_8960_PHY_REG12_SW_RESET;
- /*
- * Wait for a short time before de-asserting to allow the hardware to
- * complete its job. This much of delay should be fine for hardware to
- * assert and de-assert.
- */
- udelay(10);
- /* De-assert PHY S/W reset */
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x3f);
-
- val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
- val |= HDMI_8960_PHY_REG12_PWRDN_B;
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
- /* Wait 10 us for enabling global power for PHY */
- mb();
- udelay(10);
-
- val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
- val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
- val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
- pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80);
-
- timeout_count = 1000;
- while (--pll_lock_retry > 0) {
- /* are we there yet? */
- val = pll_read(pll, REG_HDMI_8960_PHY_PLL_STATUS0);
- if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK)
- break;
-
- udelay(1);
-
- if (--timeout_count > 0)
- continue;
-
- /*
- * PLL has still not locked.
- * Do a software reset and try again
- * Assert PLL S/W reset first
- */
- pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
- udelay(10);
- pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
-
- /*
- * Wait for a short duration for the PLL calibration
- * before checking if the PLL gets locked
- */
- udelay(350);
-
- timeout_count = 1000;
- }
-
- return 0;
-}
-
-static void hdmi_pll_disable(struct clk_hw *hw)
-{
- struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
- struct hdmi_phy *phy = pll_get_phy(pll);
- unsigned int val;
-
- DBG("");
-
- val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
- val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
- hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
-
- val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
- val |= HDMI_8960_PHY_REG12_SW_RESET;
- val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
- pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
- /* Make sure HDMI PHY/PLL are powered down */
- mb();
-}
-
-static const struct pll_rate *find_rate(unsigned long rate)
-{
- int i;
-
- for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
- if (rate > freqtbl[i].rate)
- return &freqtbl[i - 1];
-
- return &freqtbl[i - 1];
-}
-
-static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
-
- return pll->pixclk;
-}
-
-static int hdmi_pll_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
-{
- const struct pll_rate *pll_rate = find_rate(req->rate);
-
- req->rate = pll_rate->rate;
-
- return 0;
-}
-
-static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
- const struct pll_rate *pll_rate = find_rate(rate);
- int i;
-
- DBG("rate=%lu", rate);
-
- for (i = 0; i < pll_rate->num_reg; i++)
- pll_write(pll, pll_rate->conf[i].reg, pll_rate->conf[i].val);
-
- pll->pixclk = rate;
-
- return 0;
-}
-
-static const struct clk_ops hdmi_pll_ops = {
- .enable = hdmi_pll_enable,
- .disable = hdmi_pll_disable,
- .recalc_rate = hdmi_pll_recalc_rate,
- .determine_rate = hdmi_pll_determine_rate,
- .set_rate = hdmi_pll_set_rate,
-};
-
-static const struct clk_parent_data hdmi_pll_parents[] = {
- { .fw_name = "pxo", .name = "pxo_board" },
-};
-
-static struct clk_init_data pll_init = {
- .name = "hdmi_pll",
- .ops = &hdmi_pll_ops,
- .parent_data = hdmi_pll_parents,
- .num_parents = ARRAY_SIZE(hdmi_pll_parents),
- .flags = CLK_IGNORE_UNUSED,
-};
-
-int msm_hdmi_pll_8960_init(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct hdmi_pll_8960 *pll;
- int i, ret;
-
- /* sanity check: */
- for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
- if (WARN_ON(freqtbl[i].rate < freqtbl[i + 1].rate))
- return -EINVAL;
-
- pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
- if (!pll)
- return -ENOMEM;
-
- pll->mmio = msm_ioremap(pdev, "hdmi_pll");
- if (IS_ERR(pll->mmio)) {
- DRM_DEV_ERROR(dev, "failed to map pll base\n");
- return -ENOMEM;
- }
-
- pll->pdev = pdev;
- pll->clk_hw.init = &pll_init;
-
- ret = devm_clk_hw_register(dev, &pll->clk_hw);
- if (ret < 0) {
- DRM_DEV_ERROR(dev, "failed to register pll clock\n");
- return ret;
- }
-
- ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
- if (ret) {
- DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/msm/registers/display/hdmi.xml b/drivers/gpu/drm/msm/registers/display/hdmi.xml
index 0ebb96297dae..1d44aa26c833 100644
--- a/drivers/gpu/drm/msm/registers/display/hdmi.xml
+++ b/drivers/gpu/drm/msm/registers/display/hdmi.xml
@@ -564,541 +564,4 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
</domain>
-<domain name="HDMI_8x60" width="32">
- <reg32 offset="0x00000" name="PHY_REG0">
- <bitfield name="DESER_DEL_CTRL" low="2" high="4" type="uint"/>
- </reg32>
- <reg32 offset="0x00004" name="PHY_REG1">
- <bitfield name="DTEST_MUX_SEL" low="4" high="7" type="uint"/>
- <bitfield name="OUTVOL_SWING_CTRL" low="0" high="3" type="uint"/>
- </reg32>
- <reg32 offset="0x00008" name="PHY_REG2">
- <bitfield name="PD_DESER" pos="0" type="boolean"/>
- <bitfield name="PD_DRIVE_1" pos="1" type="boolean"/>
- <bitfield name="PD_DRIVE_2" pos="2" type="boolean"/>
- <bitfield name="PD_DRIVE_3" pos="3" type="boolean"/>
- <bitfield name="PD_DRIVE_4" pos="4" type="boolean"/>
- <bitfield name="PD_PLL" pos="5" type="boolean"/>
- <bitfield name="PD_PWRGEN" pos="6" type="boolean"/>
- <bitfield name="RCV_SENSE_EN" pos="7" type="boolean"/>
- </reg32>
- <reg32 offset="0x0000c" name="PHY_REG3">
- <bitfield name="PLL_ENABLE" pos="0" type="boolean"/>
- </reg32>
- <reg32 offset="0x00010" name="PHY_REG4"/>
- <reg32 offset="0x00014" name="PHY_REG5"/>
- <reg32 offset="0x00018" name="PHY_REG6"/>
- <reg32 offset="0x0001c" name="PHY_REG7"/>
- <reg32 offset="0x00020" name="PHY_REG8"/>
- <reg32 offset="0x00024" name="PHY_REG9"/>
- <reg32 offset="0x00028" name="PHY_REG10"/>
- <reg32 offset="0x0002c" name="PHY_REG11"/>
- <reg32 offset="0x00030" name="PHY_REG12">
- <bitfield name="RETIMING_EN" pos="0" type="boolean"/>
- <bitfield name="PLL_LOCK_DETECT_EN" pos="1" type="boolean"/>
- <bitfield name="FORCE_LOCK" pos="4" type="boolean"/>
- </reg32>
-</domain>
-
-<domain name="HDMI_8960" width="32">
- <!--
- some of the bitfields may be same as 8x60.. but no helpful comments
- in msm_dss_io_8960.c
- -->
- <reg32 offset="0x00000" name="PHY_REG0"/>
- <reg32 offset="0x00004" name="PHY_REG1"/>
- <reg32 offset="0x00008" name="PHY_REG2"/>
- <reg32 offset="0x0000c" name="PHY_REG3"/>
- <reg32 offset="0x00010" name="PHY_REG4"/>
- <reg32 offset="0x00014" name="PHY_REG5"/>
- <reg32 offset="0x00018" name="PHY_REG6"/>
- <reg32 offset="0x0001c" name="PHY_REG7"/>
- <reg32 offset="0x00020" name="PHY_REG8"/>
- <reg32 offset="0x00024" name="PHY_REG9"/>
- <reg32 offset="0x00028" name="PHY_REG10"/>
- <reg32 offset="0x0002c" name="PHY_REG11"/>
- <reg32 offset="0x00030" name="PHY_REG12">
- <bitfield name="SW_RESET" pos="5" type="boolean"/>
- <bitfield name="PWRDN_B" pos="7" type="boolean"/>
- </reg32>
- <reg32 offset="0x00034" name="PHY_REG_BIST_CFG"/>
- <reg32 offset="0x00038" name="PHY_DEBUG_BUS_SEL"/>
- <reg32 offset="0x0003c" name="PHY_REG_MISC0"/>
- <reg32 offset="0x00040" name="PHY_REG13"/>
- <reg32 offset="0x00044" name="PHY_REG14"/>
- <reg32 offset="0x00048" name="PHY_REG15"/>
-</domain>
-
-<domain name="HDMI_8960_PHY_PLL" width="32">
- <reg32 offset="0x00000" name="REFCLK_CFG"/>
- <reg32 offset="0x00004" name="CHRG_PUMP_CFG"/>
- <reg32 offset="0x00008" name="LOOP_FLT_CFG0"/>
- <reg32 offset="0x0000c" name="LOOP_FLT_CFG1"/>
- <reg32 offset="0x00010" name="IDAC_ADJ_CFG"/>
- <reg32 offset="0x00014" name="I_VI_KVCO_CFG"/>
- <reg32 offset="0x00018" name="PWRDN_B">
- <bitfield name="PD_PLL" pos="1" type="boolean"/>
- <bitfield name="PLL_PWRDN_B" pos="3" type="boolean"/>
- </reg32>
- <reg32 offset="0x0001c" name="SDM_CFG0"/>
- <reg32 offset="0x00020" name="SDM_CFG1"/>
- <reg32 offset="0x00024" name="SDM_CFG2"/>
- <reg32 offset="0x00028" name="SDM_CFG3"/>
- <reg32 offset="0x0002c" name="SDM_CFG4"/>
- <reg32 offset="0x00030" name="SSC_CFG0"/>
- <reg32 offset="0x00034" name="SSC_CFG1"/>
- <reg32 offset="0x00038" name="SSC_CFG2"/>
- <reg32 offset="0x0003c" name="SSC_CFG3"/>
- <reg32 offset="0x00040" name="LOCKDET_CFG0"/>
- <reg32 offset="0x00044" name="LOCKDET_CFG1"/>
- <reg32 offset="0x00048" name="LOCKDET_CFG2"/>
- <reg32 offset="0x0004c" name="VCOCAL_CFG0"/>
- <reg32 offset="0x00050" name="VCOCAL_CFG1"/>
- <reg32 offset="0x00054" name="VCOCAL_CFG2"/>
- <reg32 offset="0x00058" name="VCOCAL_CFG3"/>
- <reg32 offset="0x0005c" name="VCOCAL_CFG4"/>
- <reg32 offset="0x00060" name="VCOCAL_CFG5"/>
- <reg32 offset="0x00064" name="VCOCAL_CFG6"/>
- <reg32 offset="0x00068" name="VCOCAL_CFG7"/>
- <reg32 offset="0x0006c" name="DEBUG_SEL"/>
- <reg32 offset="0x00070" name="MISC0"/>
- <reg32 offset="0x00074" name="MISC1"/>
- <reg32 offset="0x00078" name="MISC2"/>
- <reg32 offset="0x0007c" name="MISC3"/>
- <reg32 offset="0x00080" name="MISC4"/>
- <reg32 offset="0x00084" name="MISC5"/>
- <reg32 offset="0x00088" name="MISC6"/>
- <reg32 offset="0x0008c" name="DEBUG_BUS0"/>
- <reg32 offset="0x00090" name="DEBUG_BUS1"/>
- <reg32 offset="0x00094" name="DEBUG_BUS2"/>
- <reg32 offset="0x00098" name="STATUS0">
- <bitfield name="PLL_LOCK" pos="0" type="boolean"/>
- </reg32>
- <reg32 offset="0x0009c" name="STATUS1"/>
-</domain>
-
-<domain name="HDMI_8x74" width="32">
- <!--
- seems to be all mdp5+ have same?
- -->
- <reg32 offset="0x00000" name="ANA_CFG0"/>
- <reg32 offset="0x00004" name="ANA_CFG1"/>
- <reg32 offset="0x00008" name="ANA_CFG2"/>
- <reg32 offset="0x0000c" name="ANA_CFG3"/>
- <reg32 offset="0x00010" name="PD_CTRL0"/>
- <reg32 offset="0x00014" name="PD_CTRL1"/>
- <reg32 offset="0x00018" name="GLB_CFG"/>
- <reg32 offset="0x0001c" name="DCC_CFG0"/>
- <reg32 offset="0x00020" name="DCC_CFG1"/>
- <reg32 offset="0x00024" name="TXCAL_CFG0"/>
- <reg32 offset="0x00028" name="TXCAL_CFG1"/>
- <reg32 offset="0x0002c" name="TXCAL_CFG2"/>
- <reg32 offset="0x00030" name="TXCAL_CFG3"/>
- <reg32 offset="0x00034" name="BIST_CFG0"/>
- <reg32 offset="0x0003c" name="BIST_PATN0"/>
- <reg32 offset="0x00040" name="BIST_PATN1"/>
- <reg32 offset="0x00044" name="BIST_PATN2"/>
- <reg32 offset="0x00048" name="BIST_PATN3"/>
- <reg32 offset="0x0005c" name="STATUS"/>
-</domain>
-
-<domain name="HDMI_28nm_PHY_PLL" width="32">
- <reg32 offset="0x00000" name="REFCLK_CFG"/>
- <reg32 offset="0x00004" name="POSTDIV1_CFG"/>
- <reg32 offset="0x00008" name="CHGPUMP_CFG"/>
- <reg32 offset="0x0000C" name="VCOLPF_CFG"/>
- <reg32 offset="0x00010" name="VREG_CFG"/>
- <reg32 offset="0x00014" name="PWRGEN_CFG"/>
- <reg32 offset="0x00018" name="DMUX_CFG"/>
- <reg32 offset="0x0001C" name="AMUX_CFG"/>
- <reg32 offset="0x00020" name="GLB_CFG">
- <bitfield name="PLL_PWRDN_B" pos="0" type="boolean"/>
- <bitfield name="PLL_LDO_PWRDN_B" pos="1" type="boolean"/>
- <bitfield name="PLL_PWRGEN_PWRDN_B" pos="2" type="boolean"/>
- <bitfield name="PLL_ENABLE" pos="3" type="boolean"/>
- </reg32>
- <reg32 offset="0x00024" name="POSTDIV2_CFG"/>
- <reg32 offset="0x00028" name="POSTDIV3_CFG"/>
- <reg32 offset="0x0002C" name="LPFR_CFG"/>
- <reg32 offset="0x00030" name="LPFC1_CFG"/>
- <reg32 offset="0x00034" name="LPFC2_CFG"/>
- <reg32 offset="0x00038" name="SDM_CFG0"/>
- <reg32 offset="0x0003C" name="SDM_CFG1"/>
- <reg32 offset="0x00040" name="SDM_CFG2"/>
- <reg32 offset="0x00044" name="SDM_CFG3"/>
- <reg32 offset="0x00048" name="SDM_CFG4"/>
- <reg32 offset="0x0004C" name="SSC_CFG0"/>
- <reg32 offset="0x00050" name="SSC_CFG1"/>
- <reg32 offset="0x00054" name="SSC_CFG2"/>
- <reg32 offset="0x00058" name="SSC_CFG3"/>
- <reg32 offset="0x0005C" name="LKDET_CFG0"/>
- <reg32 offset="0x00060" name="LKDET_CFG1"/>
- <reg32 offset="0x00064" name="LKDET_CFG2"/>
- <reg32 offset="0x00068" name="TEST_CFG">
- <bitfield name="PLL_SW_RESET" pos="0" type="boolean"/>
- </reg32>
- <reg32 offset="0x0006C" name="CAL_CFG0"/>
- <reg32 offset="0x00070" name="CAL_CFG1"/>
- <reg32 offset="0x00074" name="CAL_CFG2"/>
- <reg32 offset="0x00078" name="CAL_CFG3"/>
- <reg32 offset="0x0007C" name="CAL_CFG4"/>
- <reg32 offset="0x00080" name="CAL_CFG5"/>
- <reg32 offset="0x00084" name="CAL_CFG6"/>
- <reg32 offset="0x00088" name="CAL_CFG7"/>
- <reg32 offset="0x0008C" name="CAL_CFG8"/>
- <reg32 offset="0x00090" name="CAL_CFG9"/>
- <reg32 offset="0x00094" name="CAL_CFG10"/>
- <reg32 offset="0x00098" name="CAL_CFG11"/>
- <reg32 offset="0x0009C" name="EFUSE_CFG"/>
- <reg32 offset="0x000A0" name="DEBUG_BUS_SEL"/>
- <reg32 offset="0x000C0" name="STATUS"/>
-</domain>
-
-<domain name="HDMI_8996_PHY" width="32">
- <reg32 offset="0x00000" name="CFG"/>
- <reg32 offset="0x00004" name="PD_CTL"/>
- <reg32 offset="0x00008" name="MODE"/>
- <reg32 offset="0x0000C" name="MISR_CLEAR"/>
- <reg32 offset="0x00010" name="TX0_TX1_BIST_CFG0"/>
- <reg32 offset="0x00014" name="TX0_TX1_BIST_CFG1"/>
- <reg32 offset="0x00018" name="TX0_TX1_PRBS_SEED_BYTE0"/>
- <reg32 offset="0x0001C" name="TX0_TX1_PRBS_SEED_BYTE1"/>
- <reg32 offset="0x00020" name="TX0_TX1_BIST_PATTERN0"/>
- <reg32 offset="0x00024" name="TX0_TX1_BIST_PATTERN1"/>
- <reg32 offset="0x00028" name="TX2_TX3_BIST_CFG0"/>
- <reg32 offset="0x0002C" name="TX2_TX3_BIST_CFG1"/>
- <reg32 offset="0x00030" name="TX2_TX3_PRBS_SEED_BYTE0"/>
- <reg32 offset="0x00034" name="TX2_TX3_PRBS_SEED_BYTE1"/>
- <reg32 offset="0x00038" name="TX2_TX3_BIST_PATTERN0"/>
- <reg32 offset="0x0003C" name="TX2_TX3_BIST_PATTERN1"/>
- <reg32 offset="0x00040" name="DEBUG_BUS_SEL"/>
- <reg32 offset="0x00044" name="TXCAL_CFG0"/>
- <reg32 offset="0x00048" name="TXCAL_CFG1"/>
- <reg32 offset="0x0004C" name="TX0_TX1_LANE_CTL"/>
- <reg32 offset="0x00050" name="TX2_TX3_LANE_CTL"/>
- <reg32 offset="0x00054" name="LANE_BIST_CONFIG"/>
- <reg32 offset="0x00058" name="CLOCK"/>
- <reg32 offset="0x0005C" name="MISC1"/>
- <reg32 offset="0x00060" name="MISC2"/>
- <reg32 offset="0x00064" name="TX0_TX1_BIST_STATUS0"/>
- <reg32 offset="0x00068" name="TX0_TX1_BIST_STATUS1"/>
- <reg32 offset="0x0006C" name="TX0_TX1_BIST_STATUS2"/>
- <reg32 offset="0x00070" name="TX2_TX3_BIST_STATUS0"/>
- <reg32 offset="0x00074" name="TX2_TX3_BIST_STATUS1"/>
- <reg32 offset="0x00078" name="TX2_TX3_BIST_STATUS2"/>
- <reg32 offset="0x0007C" name="PRE_MISR_STATUS0"/>
- <reg32 offset="0x00080" name="PRE_MISR_STATUS1"/>
- <reg32 offset="0x00084" name="PRE_MISR_STATUS2"/>
- <reg32 offset="0x00088" name="PRE_MISR_STATUS3"/>
- <reg32 offset="0x0008C" name="POST_MISR_STATUS0"/>
- <reg32 offset="0x00090" name="POST_MISR_STATUS1"/>
- <reg32 offset="0x00094" name="POST_MISR_STATUS2"/>
- <reg32 offset="0x00098" name="POST_MISR_STATUS3"/>
- <reg32 offset="0x0009C" name="STATUS"/>
- <reg32 offset="0x000A0" name="MISC3_STATUS"/>
- <reg32 offset="0x000A4" name="MISC4_STATUS"/>
- <reg32 offset="0x000A8" name="DEBUG_BUS0"/>
- <reg32 offset="0x000AC" name="DEBUG_BUS1"/>
- <reg32 offset="0x000B0" name="DEBUG_BUS2"/>
- <reg32 offset="0x000B4" name="DEBUG_BUS3"/>
- <reg32 offset="0x000B8" name="PHY_REVISION_ID0"/>
- <reg32 offset="0x000BC" name="PHY_REVISION_ID1"/>
- <reg32 offset="0x000C0" name="PHY_REVISION_ID2"/>
- <reg32 offset="0x000C4" name="PHY_REVISION_ID3"/>
-</domain>
-
-<domain name="HDMI_PHY_QSERDES_COM" width="32">
- <reg32 offset="0x00000" name="ATB_SEL1"/>
- <reg32 offset="0x00004" name="ATB_SEL2"/>
- <reg32 offset="0x00008" name="FREQ_UPDATE"/>
- <reg32 offset="0x0000C" name="BG_TIMER"/>
- <reg32 offset="0x00010" name="SSC_EN_CENTER"/>
- <reg32 offset="0x00014" name="SSC_ADJ_PER1"/>
- <reg32 offset="0x00018" name="SSC_ADJ_PER2"/>
- <reg32 offset="0x0001C" name="SSC_PER1"/>
- <reg32 offset="0x00020" name="SSC_PER2"/>
- <reg32 offset="0x00024" name="SSC_STEP_SIZE1"/>
- <reg32 offset="0x00028" name="SSC_STEP_SIZE2"/>
- <reg32 offset="0x0002C" name="POST_DIV"/>
- <reg32 offset="0x00030" name="POST_DIV_MUX"/>
- <reg32 offset="0x00034" name="BIAS_EN_CLKBUFLR_EN"/>
- <reg32 offset="0x00038" name="CLK_ENABLE1"/>
- <reg32 offset="0x0003C" name="SYS_CLK_CTRL"/>
- <reg32 offset="0x00040" name="SYSCLK_BUF_ENABLE"/>
- <reg32 offset="0x00044" name="PLL_EN"/>
- <reg32 offset="0x00048" name="PLL_IVCO"/>
- <reg32 offset="0x0004C" name="LOCK_CMP1_MODE0"/>
- <reg32 offset="0x00050" name="LOCK_CMP2_MODE0"/>
- <reg32 offset="0x00054" name="LOCK_CMP3_MODE0"/>
- <reg32 offset="0x00058" name="LOCK_CMP1_MODE1"/>
- <reg32 offset="0x0005C" name="LOCK_CMP2_MODE1"/>
- <reg32 offset="0x00060" name="LOCK_CMP3_MODE1"/>
- <reg32 offset="0x00064" name="LOCK_CMP1_MODE2"/>
- <reg32 offset="0x00064" name="CMN_RSVD0"/>
- <reg32 offset="0x00068" name="LOCK_CMP2_MODE2"/>
- <reg32 offset="0x00068" name="EP_CLOCK_DETECT_CTRL"/>
- <reg32 offset="0x0006C" name="LOCK_CMP3_MODE2"/>
- <reg32 offset="0x0006C" name="SYSCLK_DET_COMP_STATUS"/>
- <reg32 offset="0x00070" name="BG_TRIM"/>
- <reg32 offset="0x00074" name="CLK_EP_DIV"/>
- <reg32 offset="0x00078" name="CP_CTRL_MODE0"/>
- <reg32 offset="0x0007C" name="CP_CTRL_MODE1"/>
- <reg32 offset="0x00080" name="CP_CTRL_MODE2"/>
- <reg32 offset="0x00080" name="CMN_RSVD1"/>
- <reg32 offset="0x00084" name="PLL_RCTRL_MODE0"/>
- <reg32 offset="0x00088" name="PLL_RCTRL_MODE1"/>
- <reg32 offset="0x0008C" name="PLL_RCTRL_MODE2"/>
- <reg32 offset="0x0008C" name="CMN_RSVD2"/>
- <reg32 offset="0x00090" name="PLL_CCTRL_MODE0"/>
- <reg32 offset="0x00094" name="PLL_CCTRL_MODE1"/>
- <reg32 offset="0x00098" name="PLL_CCTRL_MODE2"/>
- <reg32 offset="0x00098" name="CMN_RSVD3"/>
- <reg32 offset="0x0009C" name="PLL_CNTRL"/>
- <reg32 offset="0x000A0" name="PHASE_SEL_CTRL"/>
- <reg32 offset="0x000A4" name="PHASE_SEL_DC"/>
- <reg32 offset="0x000A8" name="CORE_CLK_IN_SYNC_SEL"/>
- <reg32 offset="0x000A8" name="BIAS_EN_CTRL_BY_PSM"/>
- <reg32 offset="0x000AC" name="SYSCLK_EN_SEL"/>
- <reg32 offset="0x000B0" name="CML_SYSCLK_SEL"/>
- <reg32 offset="0x000B4" name="RESETSM_CNTRL"/>
- <reg32 offset="0x000B8" name="RESETSM_CNTRL2"/>
- <reg32 offset="0x000BC" name="RESTRIM_CTRL"/>
- <reg32 offset="0x000C0" name="RESTRIM_CTRL2"/>
- <reg32 offset="0x000C4" name="RESCODE_DIV_NUM"/>
- <reg32 offset="0x000C8" name="LOCK_CMP_EN"/>
- <reg32 offset="0x000CC" name="LOCK_CMP_CFG"/>
- <reg32 offset="0x000D0" name="DEC_START_MODE0"/>
- <reg32 offset="0x000D4" name="DEC_START_MODE1"/>
- <reg32 offset="0x000D8" name="DEC_START_MODE2"/>
- <reg32 offset="0x000D8" name="VCOCAL_DEADMAN_CTRL"/>
- <reg32 offset="0x000DC" name="DIV_FRAC_START1_MODE0"/>
- <reg32 offset="0x000E0" name="DIV_FRAC_START2_MODE0"/>
- <reg32 offset="0x000E4" name="DIV_FRAC_START3_MODE0"/>
- <reg32 offset="0x000E8" name="DIV_FRAC_START1_MODE1"/>
- <reg32 offset="0x000EC" name="DIV_FRAC_START2_MODE1"/>
- <reg32 offset="0x000F0" name="DIV_FRAC_START3_MODE1"/>
- <reg32 offset="0x000F4" name="DIV_FRAC_START1_MODE2"/>
- <reg32 offset="0x000F4" name="VCO_TUNE_MINVAL1"/>
- <reg32 offset="0x000F8" name="DIV_FRAC_START2_MODE2"/>
- <reg32 offset="0x000F8" name="VCO_TUNE_MINVAL2"/>
- <reg32 offset="0x000FC" name="DIV_FRAC_START3_MODE2"/>
- <reg32 offset="0x000FC" name="CMN_RSVD4"/>
- <reg32 offset="0x00100" name="INTEGLOOP_INITVAL"/>
- <reg32 offset="0x00104" name="INTEGLOOP_EN"/>
- <reg32 offset="0x00108" name="INTEGLOOP_GAIN0_MODE0"/>
- <reg32 offset="0x0010C" name="INTEGLOOP_GAIN1_MODE0"/>
- <reg32 offset="0x00110" name="INTEGLOOP_GAIN0_MODE1"/>
- <reg32 offset="0x00114" name="INTEGLOOP_GAIN1_MODE1"/>
- <reg32 offset="0x00118" name="INTEGLOOP_GAIN0_MODE2"/>
- <reg32 offset="0x00118" name="VCO_TUNE_MAXVAL1"/>
- <reg32 offset="0x0011C" name="INTEGLOOP_GAIN1_MODE2"/>
- <reg32 offset="0x0011C" name="VCO_TUNE_MAXVAL2"/>
- <reg32 offset="0x00120" name="RES_TRIM_CONTROL2"/>
- <reg32 offset="0x00124" name="VCO_TUNE_CTRL"/>
- <reg32 offset="0x00128" name="VCO_TUNE_MAP"/>
- <reg32 offset="0x0012C" name="VCO_TUNE1_MODE0"/>
- <reg32 offset="0x00130" name="VCO_TUNE2_MODE0"/>
- <reg32 offset="0x00134" name="VCO_TUNE1_MODE1"/>
- <reg32 offset="0x00138" name="VCO_TUNE2_MODE1"/>
- <reg32 offset="0x0013C" name="VCO_TUNE1_MODE2"/>
- <reg32 offset="0x0013C" name="VCO_TUNE_INITVAL1"/>
- <reg32 offset="0x00140" name="VCO_TUNE2_MODE2"/>
- <reg32 offset="0x00140" name="VCO_TUNE_INITVAL2"/>
- <reg32 offset="0x00144" name="VCO_TUNE_TIMER1"/>
- <reg32 offset="0x00148" name="VCO_TUNE_TIMER2"/>
- <reg32 offset="0x0014C" name="SAR"/>
- <reg32 offset="0x00150" name="SAR_CLK"/>
- <reg32 offset="0x00154" name="SAR_CODE_OUT_STATUS"/>
- <reg32 offset="0x00158" name="SAR_CODE_READY_STATUS"/>
- <reg32 offset="0x0015C" name="CMN_STATUS"/>
- <reg32 offset="0x00160" name="RESET_SM_STATUS"/>
- <reg32 offset="0x00164" name="RESTRIM_CODE_STATUS"/>
- <reg32 offset="0x00168" name="PLLCAL_CODE1_STATUS"/>
- <reg32 offset="0x0016C" name="PLLCAL_CODE2_STATUS"/>
- <reg32 offset="0x00170" name="BG_CTRL"/>
- <reg32 offset="0x00174" name="CLK_SELECT"/>
- <reg32 offset="0x00178" name="HSCLK_SEL"/>
- <reg32 offset="0x0017C" name="INTEGLOOP_BINCODE_STATUS"/>
- <reg32 offset="0x00180" name="PLL_ANALOG"/>
- <reg32 offset="0x00184" name="CORECLK_DIV"/>
- <reg32 offset="0x00188" name="SW_RESET"/>
- <reg32 offset="0x0018C" name="CORE_CLK_EN"/>
- <reg32 offset="0x00190" name="C_READY_STATUS"/>
- <reg32 offset="0x00194" name="CMN_CONFIG"/>
- <reg32 offset="0x00198" name="CMN_RATE_OVERRIDE"/>
- <reg32 offset="0x0019C" name="SVS_MODE_CLK_SEL"/>
- <reg32 offset="0x001A0" name="DEBUG_BUS0"/>
- <reg32 offset="0x001A4" name="DEBUG_BUS1"/>
- <reg32 offset="0x001A8" name="DEBUG_BUS2"/>
- <reg32 offset="0x001AC" name="DEBUG_BUS3"/>
- <reg32 offset="0x001B0" name="DEBUG_BUS_SEL"/>
- <reg32 offset="0x001B4" name="CMN_MISC1"/>
- <reg32 offset="0x001B8" name="CMN_MISC2"/>
- <reg32 offset="0x001BC" name="CORECLK_DIV_MODE1"/>
- <reg32 offset="0x001C0" name="CORECLK_DIV_MODE2"/>
- <reg32 offset="0x001C4" name="CMN_RSVD5"/>
-</domain>
-
-
-<domain name="HDMI_PHY_QSERDES_TX_LX" width="32">
- <reg32 offset="0x00000" name="BIST_MODE_LANENO"/>
- <reg32 offset="0x00004" name="BIST_INVERT"/>
- <reg32 offset="0x00008" name="CLKBUF_ENABLE"/>
- <reg32 offset="0x0000C" name="CMN_CONTROL_ONE"/>
- <reg32 offset="0x00010" name="CMN_CONTROL_TWO"/>
- <reg32 offset="0x00014" name="CMN_CONTROL_THREE"/>
- <reg32 offset="0x00018" name="TX_EMP_POST1_LVL"/>
- <reg32 offset="0x0001C" name="TX_POST2_EMPH"/>
- <reg32 offset="0x00020" name="TX_BOOST_LVL_UP_DN"/>
- <reg32 offset="0x00024" name="HP_PD_ENABLES"/>
- <reg32 offset="0x00028" name="TX_IDLE_LVL_LARGE_AMP"/>
- <reg32 offset="0x0002C" name="TX_DRV_LVL"/>
- <reg32 offset="0x00030" name="TX_DRV_LVL_OFFSET"/>
- <reg32 offset="0x00034" name="RESET_TSYNC_EN"/>
- <reg32 offset="0x00038" name="PRE_STALL_LDO_BOOST_EN"/>
- <reg32 offset="0x0003C" name="TX_BAND"/>
- <reg32 offset="0x00040" name="SLEW_CNTL"/>
- <reg32 offset="0x00044" name="INTERFACE_SELECT"/>
- <reg32 offset="0x00048" name="LPB_EN"/>
- <reg32 offset="0x0004C" name="RES_CODE_LANE_TX"/>
- <reg32 offset="0x00050" name="RES_CODE_LANE_RX"/>
- <reg32 offset="0x00054" name="RES_CODE_LANE_OFFSET"/>
- <reg32 offset="0x00058" name="PERL_LENGTH1"/>
- <reg32 offset="0x0005C" name="PERL_LENGTH2"/>
- <reg32 offset="0x00060" name="SERDES_BYP_EN_OUT"/>
- <reg32 offset="0x00064" name="DEBUG_BUS_SEL"/>
- <reg32 offset="0x00068" name="HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN"/>
- <reg32 offset="0x0006C" name="TX_POL_INV"/>
- <reg32 offset="0x00070" name="PARRATE_REC_DETECT_IDLE_EN"/>
- <reg32 offset="0x00074" name="BIST_PATTERN1"/>
- <reg32 offset="0x00078" name="BIST_PATTERN2"/>
- <reg32 offset="0x0007C" name="BIST_PATTERN3"/>
- <reg32 offset="0x00080" name="BIST_PATTERN4"/>
- <reg32 offset="0x00084" name="BIST_PATTERN5"/>
- <reg32 offset="0x00088" name="BIST_PATTERN6"/>
- <reg32 offset="0x0008C" name="BIST_PATTERN7"/>
- <reg32 offset="0x00090" name="BIST_PATTERN8"/>
- <reg32 offset="0x00094" name="LANE_MODE"/>
- <reg32 offset="0x00098" name="IDAC_CAL_LANE_MODE"/>
- <reg32 offset="0x0009C" name="IDAC_CAL_LANE_MODE_CONFIGURATION"/>
- <reg32 offset="0x000A0" name="ATB_SEL1"/>
- <reg32 offset="0x000A4" name="ATB_SEL2"/>
- <reg32 offset="0x000A8" name="RCV_DETECT_LVL"/>
- <reg32 offset="0x000AC" name="RCV_DETECT_LVL_2"/>
- <reg32 offset="0x000B0" name="PRBS_SEED1"/>
- <reg32 offset="0x000B4" name="PRBS_SEED2"/>
- <reg32 offset="0x000B8" name="PRBS_SEED3"/>
- <reg32 offset="0x000BC" name="PRBS_SEED4"/>
- <reg32 offset="0x000C0" name="RESET_GEN"/>
- <reg32 offset="0x000C4" name="RESET_GEN_MUXES"/>
- <reg32 offset="0x000C8" name="TRAN_DRVR_EMP_EN"/>
- <reg32 offset="0x000CC" name="TX_INTERFACE_MODE"/>
- <reg32 offset="0x000D0" name="PWM_CTRL"/>
- <reg32 offset="0x000D4" name="PWM_ENCODED_OR_DATA"/>
- <reg32 offset="0x000D8" name="PWM_GEAR_1_DIVIDER_BAND2"/>
- <reg32 offset="0x000DC" name="PWM_GEAR_2_DIVIDER_BAND2"/>
- <reg32 offset="0x000E0" name="PWM_GEAR_3_DIVIDER_BAND2"/>
- <reg32 offset="0x000E4" name="PWM_GEAR_4_DIVIDER_BAND2"/>
- <reg32 offset="0x000E8" name="PWM_GEAR_1_DIVIDER_BAND0_1"/>
- <reg32 offset="0x000EC" name="PWM_GEAR_2_DIVIDER_BAND0_1"/>
- <reg32 offset="0x000F0" name="PWM_GEAR_3_DIVIDER_BAND0_1"/>
- <reg32 offset="0x000F4" name="PWM_GEAR_4_DIVIDER_BAND0_1"/>
- <reg32 offset="0x000F8" name="VMODE_CTRL1"/>
- <reg32 offset="0x000FC" name="VMODE_CTRL2"/>
- <reg32 offset="0x00100" name="TX_ALOG_INTF_OBSV_CNTL"/>
- <reg32 offset="0x00104" name="BIST_STATUS"/>
- <reg32 offset="0x00108" name="BIST_ERROR_COUNT1"/>
- <reg32 offset="0x0010C" name="BIST_ERROR_COUNT2"/>
- <reg32 offset="0x00110" name="TX_ALOG_INTF_OBSV"/>
-</domain>
-
-<domain name="HDMI_8998_PHY" width="32">
- <reg32 offset="0x00000" name="CFG"/>
- <reg32 offset="0x00004" name="PD_CTL"/>
- <reg32 offset="0x00010" name="MODE"/>
- <reg32 offset="0x0005C" name="CLOCK"/>
- <reg32 offset="0x00068" name="CMN_CTRL"/>
- <reg32 offset="0x000B4" name="STATUS"/>
-</domain>
-
-<domain name="HDMI_8998_PHY_QSERDES_COM" width="32">
- <reg32 offset="0x0000" name="ATB_SEL1"/>
- <reg32 offset="0x0004" name="ATB_SEL2"/>
- <reg32 offset="0x0008" name="FREQ_UPDATE"/>
- <reg32 offset="0x000C" name="BG_TIMER"/>
- <reg32 offset="0x0010" name="SSC_EN_CENTER"/>
- <reg32 offset="0x0014" name="SSC_ADJ_PER1"/>
- <reg32 offset="0x0018" name="SSC_ADJ_PER2"/>
- <reg32 offset="0x001C" name="SSC_PER1"/>
- <reg32 offset="0x0020" name="SSC_PER2"/>
- <reg32 offset="0x0024" name="SSC_STEP_SIZE1"/>
- <reg32 offset="0x0028" name="SSC_STEP_SIZE2"/>
- <reg32 offset="0x002C" name="POST_DIV"/>
- <reg32 offset="0x0030" name="POST_DIV_MUX"/>
- <reg32 offset="0x0034" name="BIAS_EN_CLKBUFLR_EN"/>
- <reg32 offset="0x0038" name="CLK_ENABLE1"/>
- <reg32 offset="0x003C" name="SYS_CLK_CTRL"/>
- <reg32 offset="0x0040" name="SYSCLK_BUF_ENABLE"/>
- <reg32 offset="0x0044" name="PLL_EN"/>
- <reg32 offset="0x0048" name="PLL_IVCO"/>
- <reg32 offset="0x004C" name="CMN_IETRIM"/>
- <reg32 offset="0x0050" name="CMN_IPTRIM"/>
- <reg32 offset="0x0060" name="CP_CTRL_MODE0"/>
- <reg32 offset="0x0064" name="CP_CTRL_MODE1"/>
- <reg32 offset="0x0068" name="PLL_RCTRL_MODE0"/>
- <reg32 offset="0x006C" name="PLL_RCTRL_MODE1"/>
- <reg32 offset="0x0070" name="PLL_CCTRL_MODE0"/>
- <reg32 offset="0x0074" name="PLL_CCTRL_MODE1"/>
- <reg32 offset="0x0078" name="PLL_CNTRL"/>
- <reg32 offset="0x007C" name="BIAS_EN_CTRL_BY_PSM"/>
- <reg32 offset="0x0080" name="SYSCLK_EN_SEL"/>
- <reg32 offset="0x0084" name="CML_SYSCLK_SEL"/>
- <reg32 offset="0x0088" name="RESETSM_CNTRL"/>
- <reg32 offset="0x008C" name="RESETSM_CNTRL2"/>
- <reg32 offset="0x0090" name="LOCK_CMP_EN"/>
- <reg32 offset="0x0094" name="LOCK_CMP_CFG"/>
- <reg32 offset="0x0098" name="LOCK_CMP1_MODE0"/>
- <reg32 offset="0x009C" name="LOCK_CMP2_MODE0"/>
- <reg32 offset="0x00A0" name="LOCK_CMP3_MODE0"/>
- <reg32 offset="0x00B0" name="DEC_START_MODE0"/>
- <reg32 offset="0x00B4" name="DEC_START_MODE1"/>
- <reg32 offset="0x00B8" name="DIV_FRAC_START1_MODE0"/>
- <reg32 offset="0x00BC" name="DIV_FRAC_START2_MODE0"/>
- <reg32 offset="0x00C0" name="DIV_FRAC_START3_MODE0"/>
- <reg32 offset="0x00C4" name="DIV_FRAC_START1_MODE1"/>
- <reg32 offset="0x00C8" name="DIV_FRAC_START2_MODE1"/>
- <reg32 offset="0x00CC" name="DIV_FRAC_START3_MODE1"/>
- <reg32 offset="0x00D0" name="INTEGLOOP_INITVAL"/>
- <reg32 offset="0x00D4" name="INTEGLOOP_EN"/>
- <reg32 offset="0x00D8" name="INTEGLOOP_GAIN0_MODE0"/>
- <reg32 offset="0x00DC" name="INTEGLOOP_GAIN1_MODE0"/>
- <reg32 offset="0x00E0" name="INTEGLOOP_GAIN0_MODE1"/>
- <reg32 offset="0x00E4" name="INTEGLOOP_GAIN1_MODE1"/>
- <reg32 offset="0x00E8" name="VCOCAL_DEADMAN_CTRL"/>
- <reg32 offset="0x00EC" name="VCO_TUNE_CTRL"/>
- <reg32 offset="0x00F0" name="VCO_TUNE_MAP"/>
- <reg32 offset="0x0124" name="CMN_STATUS"/>
- <reg32 offset="0x0128" name="RESET_SM_STATUS"/>
- <reg32 offset="0x0138" name="CLK_SEL"/>
- <reg32 offset="0x013C" name="HSCLK_SEL"/>
- <reg32 offset="0x0148" name="CORECLK_DIV_MODE0"/>
- <reg32 offset="0x0150" name="SW_RESET"/>
- <reg32 offset="0x0154" name="CORE_CLK_EN"/>
- <reg32 offset="0x0158" name="C_READY_STATUS"/>
- <reg32 offset="0x015C" name="CMN_CONFIG"/>
- <reg32 offset="0x0164" name="SVS_MODE_CLK_SEL"/>
-</domain>
-
-<domain name="HDMI_8998_PHY_TXn" width="32">
- <reg32 offset="0x0000" name="EMP_POST1_LVL"/>
- <reg32 offset="0x0008" name="INTERFACE_SELECT_TX_BAND"/>
- <reg32 offset="0x000C" name="CLKBUF_TERM_ENABLE"/>
- <reg32 offset="0x0014" name="DRV_LVL_RES_CODE_OFFSET"/>
- <reg32 offset="0x0018" name="DRV_LVL"/>
- <reg32 offset="0x001C" name="LANE_CONFIG"/>
- <reg32 offset="0x0024" name="PRE_DRIVER_1"/>
- <reg32 offset="0x0028" name="PRE_DRIVER_2"/>
- <reg32 offset="0x002C" name="LANE_MODE"/>
-</domain>
-
</database>
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index 60a0ead127fa..2c0f5547c5de 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -42,6 +42,20 @@ config PHY_QCOM_IPQ806X_SATA
depends on OF
select GENERIC_PHY
+config PHY_QCOM_HDMI
+ tristate "Qualcomm MSM8x60/MSM8960/MSM8974 HDMI PHY driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on OF
+ depends on COMMON_CLK
+ default DRM_MSM_HDMI && ARCH_QCOM && ARM
+ select GENERIC_PHY
+ help
+ Enable this to support the Qualcomm HDMI PHY presend on 32-bit platforms:
+ MSM8260, MSM8660, MSM8960, MSM8974, APQ8060, APQ8064, APQ8074 and APQ8084.
+
+ Note, this driver is not used on MSM899x platforms, which use
+ PHY_QCOM_QMP_HDMI instead.
+
config PHY_QCOM_PCIE2
tristate "Qualcomm PCIe Gen2 PHY Driver"
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
@@ -68,6 +82,16 @@ config PHY_QCOM_QMP_COMBO
Enable this to support the QMP Combo PHY transceiver that is used
with USB3 and DisplayPort controllers on Qualcomm chips.
+config PHY_QCOM_QMP_HDMI
+ tristate "Qualcomm QMP HDMI PHY Driver"
+ default PHY_QCOM_QMP && DRM_MSM_HDMI
+ help
+ Enable this to support the QMP HDMI PHY transceiver that is used
+ with HDMI output on Qualcomm MSM8996 and MSM8998 chips.
+
+ Note, this driver is not used on Qualcomm 32-bit platforms, which use
+ PHY_QCOM_HDMI instead.
+
config PHY_QCOM_QMP_PCIE
tristate "Qualcomm QMP PCIe PHY Driver"
depends on PCI || COMPILE_TEST
diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index b71a6a0bed3f..60946c14514a 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -4,17 +4,31 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_QCOM_EDP) += phy-qcom-edp.o
obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
+obj-$(CONFIG_PHY_QCOM_HDMI) += phy-qcom-hdmi.o
+
+phy-qcom-hdmi-y := \
+ phy-qcom-hdmi-preqmp.o \
+ phy-qcom-hdmi-28hpm.o \
+ phy-qcom-hdmi-28lpm.o \
+ phy-qcom-hdmi-45nm.o \
+
obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o
obj-$(CONFIG_PHY_QCOM_M31_EUSB) += phy-qcom-m31-eusb2.o
obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o phy-qcom-qmp-usbc.o
+obj-$(CONFIG_PHY_QCOM_QMP_HDMI) += phy-qcom-qmp-hdmi.o
obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o
obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) += phy-qcom-qmp-pcie-msm8996.o
obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o
obj-$(CONFIG_PHY_QCOM_QMP_USB) += phy-qcom-qmp-usb.o
obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) += phy-qcom-qmp-usb-legacy.o
+phy-qcom-qmp-hdmi-y := \
+ phy-qcom-qmp-hdmi-base.o \
+ phy-qcom-qmp-hdmi-msm8996.o \
+ phy-qcom-qmp-hdmi-msm8998.o \
+
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) += phy-qcom-uniphy-pcie-28lp.o
diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c b/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c
new file mode 100644
index 000000000000..720757f8f393
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ * Author: Rob Clark <robdclark@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+
+#include "phy-qcom-hdmi-preqmp.h"
+
+#define REG_HDMI_8x74_ANA_CFG0 0x00000000
+#define REG_HDMI_8x74_ANA_CFG1 0x00000004
+#define REG_HDMI_8x74_ANA_CFG2 0x00000008
+#define REG_HDMI_8x74_ANA_CFG3 0x0000000c
+#define REG_HDMI_8x74_PD_CTRL0 0x00000010
+#define REG_HDMI_8x74_PD_CTRL1 0x00000014
+#define REG_HDMI_8x74_GLB_CFG 0x00000018
+#define REG_HDMI_8x74_DCC_CFG0 0x0000001c
+#define REG_HDMI_8x74_DCC_CFG1 0x00000020
+#define REG_HDMI_8x74_TXCAL_CFG0 0x00000024
+#define REG_HDMI_8x74_TXCAL_CFG1 0x00000028
+#define REG_HDMI_8x74_TXCAL_CFG2 0x0000002c
+#define REG_HDMI_8x74_TXCAL_CFG3 0x00000030
+#define REG_HDMI_8x74_BIST_CFG0 0x00000034
+#define REG_HDMI_8x74_BIST_PATN0 0x0000003c
+#define REG_HDMI_8x74_BIST_PATN1 0x00000040
+#define REG_HDMI_8x74_BIST_PATN2 0x00000044
+#define REG_HDMI_8x74_BIST_PATN3 0x00000048
+#define REG_HDMI_8x74_STATUS 0x0000005c
+
+static int qcom_hdmi_msm8974_phy_power_on(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ writel(0x1b, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG0);
+ writel(0xf2, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG1);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_CFG0);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN0);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN1);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN2);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN3);
+ writel(0x20, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL1);
+
+ return 0;
+}
+
+static int qcom_hdmi_msm8974_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ writel(0x7f, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL0);
+
+ return 0;
+}
+
+const struct clk_parent_data msm8974_hdmi_pll_parent = {
+ .fw_name = "xo", .name = "xo_board",
+};
+
+const struct qcom_hdmi_preqmp_cfg msm8974_hdmi_phy_cfg = {
+ .clk_names = { "iface", "alt_iface" },
+ .num_clks = 2,
+
+ .reg_names = { "vddio", "core-vdda" },
+ .reg_init_load = { 100000, 10000 },
+ .num_regs = 2,
+
+ .power_on = qcom_hdmi_msm8974_phy_power_on,
+ .power_off = qcom_hdmi_msm8974_phy_power_off,
+
+ .pll_parent = &msm8974_hdmi_pll_parent,
+};
diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c b/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c
new file mode 100644
index 000000000000..8f1dcd884169
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ * Author: Rob Clark <robdclark@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+
+#include "phy-qcom-hdmi-preqmp.h"
+
+#define REG_HDMI_8960_PHY_REG0 0x00000000
+
+#define REG_HDMI_8960_PHY_REG1 0x00000004
+
+#define REG_HDMI_8960_PHY_REG2 0x00000008
+
+#define REG_HDMI_8960_PHY_REG3 0x0000000c
+
+#define REG_HDMI_8960_PHY_REG4 0x00000010
+
+#define REG_HDMI_8960_PHY_REG5 0x00000014
+
+#define REG_HDMI_8960_PHY_REG6 0x00000018
+
+#define REG_HDMI_8960_PHY_REG7 0x0000001c
+
+#define REG_HDMI_8960_PHY_REG8 0x00000020
+
+#define REG_HDMI_8960_PHY_REG9 0x00000024
+
+#define REG_HDMI_8960_PHY_REG10 0x00000028
+
+#define REG_HDMI_8960_PHY_REG11 0x0000002c
+
+#define REG_HDMI_8960_PHY_REG12 0x00000030
+#define HDMI_8960_PHY_REG12_SW_RESET 0x00000020
+#define HDMI_8960_PHY_REG12_PWRDN_B 0x00000080
+
+#define REG_HDMI_8960_PHY_REG_BIST_CFG 0x00000034
+
+#define REG_HDMI_8960_PHY_DEBUG_BUS_SEL 0x00000038
+
+#define REG_HDMI_8960_PHY_REG_MISC0 0x0000003c
+
+#define REG_HDMI_8960_PHY_REG13 0x00000040
+
+#define REG_HDMI_8960_PHY_REG14 0x00000044
+
+#define REG_HDMI_8960_PHY_REG15 0x00000048
+
+#define REG_HDMI_8960_PHY_PLL_REFCLK_CFG 0x00000000
+
+#define REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG 0x00000004
+
+#define REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 0x00000008
+
+#define REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 0x0000000c
+
+#define REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG 0x00000010
+
+#define REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG 0x00000014
+
+#define REG_HDMI_8960_PHY_PLL_PWRDN_B 0x00000018
+#define HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL 0x00000002
+#define HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B 0x00000008
+
+#define REG_HDMI_8960_PHY_PLL_SDM_CFG0 0x0000001c
+
+#define REG_HDMI_8960_PHY_PLL_SDM_CFG1 0x00000020
+
+#define REG_HDMI_8960_PHY_PLL_SDM_CFG2 0x00000024
+
+#define REG_HDMI_8960_PHY_PLL_SDM_CFG3 0x00000028
+
+#define REG_HDMI_8960_PHY_PLL_SDM_CFG4 0x0000002c
+
+#define REG_HDMI_8960_PHY_PLL_SSC_CFG0 0x00000030
+
+#define REG_HDMI_8960_PHY_PLL_SSC_CFG1 0x00000034
+
+#define REG_HDMI_8960_PHY_PLL_SSC_CFG2 0x00000038
+
+#define REG_HDMI_8960_PHY_PLL_SSC_CFG3 0x0000003c
+
+#define REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 0x00000040
+
+#define REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 0x00000044
+
+#define REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 0x00000048
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 0x0000004c
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 0x00000050
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 0x00000054
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 0x00000058
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 0x0000005c
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 0x00000060
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 0x00000064
+
+#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 0x00000068
+
+#define REG_HDMI_8960_PHY_PLL_DEBUG_SEL 0x0000006c
+
+#define REG_HDMI_8960_PHY_PLL_MISC0 0x00000070
+
+#define REG_HDMI_8960_PHY_PLL_MISC1 0x00000074
+
+#define REG_HDMI_8960_PHY_PLL_MISC2 0x00000078
+
+#define REG_HDMI_8960_PHY_PLL_MISC3 0x0000007c
+
+#define REG_HDMI_8960_PHY_PLL_MISC4 0x00000080
+
+#define REG_HDMI_8960_PHY_PLL_MISC5 0x00000084
+
+#define REG_HDMI_8960_PHY_PLL_MISC6 0x00000088
+
+#define REG_HDMI_8960_PHY_PLL_DEBUG_BUS0 0x0000008c
+
+#define REG_HDMI_8960_PHY_PLL_DEBUG_BUS1 0x00000090
+
+#define REG_HDMI_8960_PHY_PLL_DEBUG_BUS2 0x00000094
+
+#define REG_HDMI_8960_PHY_PLL_STATUS0 0x00000098
+#define HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK 0x00000001
+
+#define REG_HDMI_8960_PHY_PLL_STATUS1 0x0000009c
+
+/* FIXME: verify boundaries */
+#define HDMI_8960_VCO_MAX_FREQ 1125000000UL
+#define HDMI_8960_VCO_MIN_FREQ 540000000UL
+
+#define HDMI_8960_COMMON_DIV 5
+
+static inline void write16(u16 val, void __iomem *reg)
+{
+ writel(val & 0xff, reg);
+ writel(val >> 8, reg + 4);
+}
+
+static inline void write24(u32 val, void __iomem *reg)
+{
+ writel(val & 0xff, reg);
+ writel((val >> 8) & 0xff, reg + 4);
+ writel(val >> 16, reg + 8);
+}
+
+static inline u32 read24(void __iomem *reg)
+{
+ u32 val = readl(reg);
+
+ val |= readl(reg + 4) << 8;
+ val |= readl(reg + 8) << 16;
+
+ return val;
+}
+
+/* This function is close to UNIPHY, but it has slighly different fields */
+static unsigned long qcom_28lpm_recalc(struct qcom_hdmi_preqmp_phy *hdmi_phy,
+ unsigned long parent_rate)
+{
+ unsigned long rate;
+ u32 refclk_cfg;
+ u32 dc_offset;
+ u64 fraq_n;
+ u32 val;
+
+ refclk_cfg = readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_REFCLK_CFG);
+ if (refclk_cfg & BIT(1))
+ parent_rate /= 2;
+ if (refclk_cfg & BIT(3))
+ parent_rate *= 2;
+
+ val = readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG0);
+ if (val & 0x40) {
+ dc_offset = val & 0x3f;
+ fraq_n = 0;
+ } else {
+ dc_offset = readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG1) & 0x3f;
+ fraq_n = read24(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG2);
+ }
+
+ rate = (dc_offset + 1) * parent_rate;
+ rate += mult_frac(fraq_n, parent_rate, 0x10000);
+
+ return rate;
+}
+
+/* This function is close to UNIPHY, but it has slighly different fields */
+static int qcom_28lpm_set_rate(struct qcom_hdmi_preqmp_phy *hdmi_phy, unsigned long parent_rate,
+ unsigned long vco_freq, u32 div_idx)
+{
+ unsigned int pixclk = hdmi_phy->hdmi_opts.tmds_char_rate;
+ unsigned int int_ref_freq;
+ unsigned int div;
+ unsigned int dc_offset;
+ unsigned int sdm_freq_seed;
+ unsigned int val;
+ bool sdm_mode = false;
+ u32 refclk_cfg;
+ u32 lf_cfg0;
+ u32 lf_cfg1;
+
+ dev_dbg(hdmi_phy->dev, "rate=%u, div = %d, vco = %lu", pixclk, div, vco_freq);
+
+ if (vco_freq % (parent_rate / 2) == 0) {
+ refclk_cfg = 0x2;
+ int_ref_freq = parent_rate / 2;
+ } else {
+ refclk_cfg = 0x8;
+ int_ref_freq = parent_rate * 2;
+ sdm_mode = true;
+ }
+
+ dc_offset = vco_freq / int_ref_freq - 1;
+ sdm_freq_seed = vco_freq - (dc_offset + 1) * int_ref_freq;
+ sdm_freq_seed = mult_frac(sdm_freq_seed, 0x10000, int_ref_freq);
+
+ val = (div_idx << 4) | refclk_cfg;
+ writel(val, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_REFCLK_CFG);
+
+ lf_cfg0 = dc_offset >= 30 ? 0 : (dc_offset >= 16 ? 0x10 : 0x20);
+ lf_cfg0 += sdm_mode ? 0 : 1;
+
+ /* XXX: 0xc3 instead of 0x33 for qcs404 */
+ lf_cfg1 = dc_offset >= 30 ? 0x33 : (dc_offset >= 16 ? 0xbb : 0xf9);
+
+ writel(lf_cfg0,
+ hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0);
+ writel(lf_cfg1,
+ hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1);
+
+ writel((sdm_mode ? 0 : 0x40) | dc_offset,
+ hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG0);
+ writel(0x40 | dc_offset,
+ hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG1);
+
+ write24(sdm_freq_seed, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG2);
+
+ write16(vco_freq / 1000, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0);
+
+ writel(0x3b, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2);
+
+ return 0;
+}
+
+static const unsigned int qcom_hdmi_8960_divs[] = {1, 2, 4, 6};
+
+static unsigned long qcom_hdmi_8960_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = hw_clk_to_phy(hw);
+ u32 div_idx = readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_REFCLK_CFG);
+ unsigned long rate = qcom_28lpm_recalc(hdmi_phy, parent_rate);
+
+ return rate / HDMI_8960_COMMON_DIV / qcom_hdmi_8960_divs[div_idx >> 4];
+}
+
+static int qcom_hdmi_8960_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long long min_freq = HDMI_8960_VCO_MIN_FREQ / HDMI_8960_COMMON_DIV;
+ unsigned long long max_freq = HDMI_8960_VCO_MAX_FREQ / HDMI_8960_COMMON_DIV;
+
+ req->rate = clamp(req->rate, min_freq / 6, max_freq);
+
+ return 0;
+}
+
+static const struct clk_ops qcom_hdmi_8960_pll_ops = {
+ .recalc_rate = qcom_hdmi_8960_pll_recalc_rate,
+ .determine_rate = qcom_hdmi_8960_pll_determine_rate,
+};
+
+static int qcom_hdmi_msm8960_phy_pll_enable(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ int pll_lock_retry = 10;
+ unsigned int val;
+ int ret;
+
+ /* Assert PLL S/W reset */
+ writel(0x8d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2);
+ writel(0x10, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0);
+ writel(0x1a, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1);
+
+ /* Wait for a short time before de-asserting
+ * to allow the hardware to complete its job.
+ * This much of delay should be fine for hardware
+ * to assert and de-assert.
+ */
+ udelay(10);
+
+ /* De-assert PLL S/W reset */
+ writel(0x0d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2);
+
+ val = readl(hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+ val |= HDMI_8960_PHY_REG12_SW_RESET;
+ /* Assert PHY S/W reset */
+ writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+ val &= ~HDMI_8960_PHY_REG12_SW_RESET;
+ /*
+ * Wait for a short time before de-asserting to allow the hardware to
+ * complete its job. This much of delay should be fine for hardware to
+ * assert and de-assert.
+ */
+ udelay(10);
+ /* De-assert PHY S/W reset */
+ writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+ writel(0x3f, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2);
+
+ val = readl(hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+ val |= HDMI_8960_PHY_REG12_PWRDN_B;
+ writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+ /* Wait 10 us for enabling global power for PHY */
+ mb();
+ udelay(10);
+
+ val = readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B);
+ val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
+ val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
+ writel(val, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B);
+ writel(0x80, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2);
+
+ while (--pll_lock_retry > 0) {
+ ret = readl_poll_timeout(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_STATUS0,
+ val, val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK,
+ 1, 1000);
+ if (!ret)
+ break;
+
+ /*
+ * PLL has still not locked.
+ * Do a software reset and try again
+ * Assert PLL S/W reset first
+ */
+ writel(0x8d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2);
+ udelay(10);
+ writel(0x0d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2);
+
+ /*
+ * Wait for a short duration for the PLL calibration
+ * before checking if the PLL gets locked
+ */
+ udelay(350);
+ }
+
+ return ret;
+}
+
+static int qcom_hdmi_msm8960_phy_find_div(unsigned long long pixclk)
+{
+ unsigned long long min_freq = HDMI_8960_VCO_MIN_FREQ / HDMI_8960_COMMON_DIV;
+ int i;
+
+ if (pixclk > HDMI_8960_VCO_MAX_FREQ / HDMI_8960_COMMON_DIV)
+ return -E2BIG;
+
+ for (i = 0; i < ARRAY_SIZE(qcom_hdmi_8960_divs); i++) {
+ if (pixclk >= min_freq / qcom_hdmi_8960_divs[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int qcom_hdmi_msm8960_phy_set_rate(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ unsigned long long pixclk = hdmi_phy->hdmi_opts.tmds_char_rate;
+ /* XXX: 19.2 for qcs404 */
+ unsigned long parent_rate = 27000000;
+ unsigned long vco_freq;
+ int div_idx;
+ u32 div;
+
+ div_idx = qcom_hdmi_msm8960_phy_find_div(pixclk);
+ if (WARN_ON(div_idx < 0))
+ return div_idx;
+
+ div = qcom_hdmi_8960_divs[div_idx];
+ vco_freq = pixclk * HDMI_8960_COMMON_DIV * div;
+
+ return qcom_28lpm_set_rate(hdmi_phy, parent_rate, vco_freq, div_idx);
+}
+
+static void qcom_hdmi_msm8960_phy_pll_disable(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ unsigned int val;
+
+ val = readl(hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+ val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
+ writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12);
+
+ val = readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B);
+ val |= HDMI_8960_PHY_REG12_SW_RESET;
+ val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
+ writel(val, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B);
+ /* Make sure HDMI PHY/PLL are powered down */
+ mb();
+}
+
+static int qcom_hdmi_msm8960_phy_power_on(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ int ret;
+
+ ret = qcom_hdmi_msm8960_phy_set_rate(hdmi_phy);
+ if (ret)
+ return ret;
+
+ ret = qcom_hdmi_msm8960_phy_pll_enable(hdmi_phy);
+ if (ret)
+ return ret;
+
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2);
+ writel(0x1b, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG0);
+ writel(0xf2, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG1);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG4);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG5);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG6);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG7);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG8);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG9);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG10);
+ writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG11);
+ writel(0x20, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG3);
+
+ return 0;
+}
+
+static int qcom_hdmi_msm8960_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ writel(0x7f, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2);
+
+ qcom_hdmi_msm8960_phy_pll_disable(hdmi_phy);
+
+ return 0;
+}
+
+const struct clk_parent_data msm8960_hdmi_pll_parent = {
+ .fw_name = "pxo", .name = "pxo_board",
+};
+
+const struct qcom_hdmi_preqmp_cfg msm8960_hdmi_phy_cfg = {
+ .clk_names = { "slave_iface" },
+ .num_clks = 1,
+
+ .reg_names = { "core-vdda" },
+ .num_regs = 1,
+
+ .power_on = qcom_hdmi_msm8960_phy_power_on,
+ .power_off = qcom_hdmi_msm8960_phy_power_off,
+
+ .pll_ops = &qcom_hdmi_8960_pll_ops,
+ .pll_parent = &msm8960_hdmi_pll_parent,
+};
diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c b/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c
new file mode 100644
index 000000000000..bb7834d1d421
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ * Author: Rob Clark <robdclark@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+
+#include "phy-qcom-hdmi-preqmp.h"
+
+#define REG_HDMI_8x60_PHY_REG0 0x00000000
+#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c
+
+#define REG_HDMI_8x60_PHY_REG1 0x00000004
+#define HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK 0x000000f0
+#define HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK 0x0000000f
+
+#define REG_HDMI_8x60_PHY_REG2 0x00000008
+#define HDMI_8x60_PHY_REG2_PD_DESER 0x00000001
+#define HDMI_8x60_PHY_REG2_PD_DRIVE_1 0x00000002
+#define HDMI_8x60_PHY_REG2_PD_DRIVE_2 0x00000004
+#define HDMI_8x60_PHY_REG2_PD_DRIVE_3 0x00000008
+#define HDMI_8x60_PHY_REG2_PD_DRIVE_4 0x00000010
+#define HDMI_8x60_PHY_REG2_PD_PLL 0x00000020
+#define HDMI_8x60_PHY_REG2_PD_PWRGEN 0x00000040
+#define HDMI_8x60_PHY_REG2_RCV_SENSE_EN 0x00000080
+
+#define REG_HDMI_8x60_PHY_REG3 0x0000000c
+#define HDMI_8x60_PHY_REG3_PLL_ENABLE 0x00000001
+
+#define REG_HDMI_8x60_PHY_REG4 0x00000010
+
+#define REG_HDMI_8x60_PHY_REG5 0x00000014
+
+#define REG_HDMI_8x60_PHY_REG6 0x00000018
+
+#define REG_HDMI_8x60_PHY_REG7 0x0000001c
+
+#define REG_HDMI_8x60_PHY_REG8 0x00000020
+
+#define REG_HDMI_8x60_PHY_REG9 0x00000024
+
+#define REG_HDMI_8x60_PHY_REG10 0x00000028
+
+#define REG_HDMI_8x60_PHY_REG11 0x0000002c
+
+#define REG_HDMI_8x60_PHY_REG12 0x00000030
+#define HDMI_8x60_PHY_REG12_RETIMING_EN 0x00000001
+#define HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN 0x00000002
+#define HDMI_8x60_PHY_REG12_FORCE_LOCK 0x00000010
+
+static int qcom_hdmi_msm8x60_phy_power_on(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ unsigned long pixclock = hdmi_phy->hdmi_opts.tmds_char_rate;
+
+ /* De-serializer delay D/C for non-lbk mode: */
+ writel(FIELD_PREP(HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK, 3),
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG0);
+
+ if (pixclock == 27 * HZ_PER_MHZ) {
+ /* video_format == HDMI_VFRMT_720x480p60_16_9 */
+ writel(FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) |
+ FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 3),
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG1);
+ } else {
+ writel(FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) |
+ FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 4),
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG1);
+ }
+
+ /* No matter what, start from the power down mode: */
+ writel(HDMI_8x60_PHY_REG2_PD_PWRGEN |
+ HDMI_8x60_PHY_REG2_PD_PLL |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
+ HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+
+ /* Turn PowerGen on: */
+ writel(HDMI_8x60_PHY_REG2_PD_PLL |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
+ HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+
+ /* Turn PLL power on: */
+ writel(HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
+ HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+
+ /* Write to HIGH after PLL power down de-assert: */
+ writel(HDMI_8x60_PHY_REG3_PLL_ENABLE,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG3);
+
+ /* ASIC power on; PHY REG9 = 0 */
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG9);
+
+ /* Enable PLL lock detect, PLL lock det will go high after lock
+ * Enable the re-time logic
+ */
+ writel(HDMI_8x60_PHY_REG12_RETIMING_EN |
+ HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG12);
+
+ /* Drivers are on: */
+ writel(HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+
+ /* If the RX detector is needed: */
+ writel(HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
+ HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG4);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG5);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG6);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG7);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG8);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG9);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG10);
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG11);
+
+ /* If we want to use lock enable based on counting: */
+ writel(HDMI_8x60_PHY_REG12_RETIMING_EN |
+ HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN |
+ HDMI_8x60_PHY_REG12_FORCE_LOCK,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG12);
+
+ return 0;
+}
+
+static int qcom_hdmi_msm8x60_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ /* Turn off Driver */
+ writel(HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
+ HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+ udelay(10);
+ /* Disable PLL */
+ writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG3);
+ /* Power down PHY, but keep RX-sense: */
+ writel(HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
+ HDMI_8x60_PHY_REG2_PD_PWRGEN |
+ HDMI_8x60_PHY_REG2_PD_PLL |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
+ HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
+ HDMI_8x60_PHY_REG2_PD_DESER,
+ hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2);
+
+ return 0;
+}
+
+const struct qcom_hdmi_preqmp_cfg msm8x60_hdmi_phy_cfg = {
+ .clk_names = { "slave_iface" },
+ .num_clks = 1,
+
+ .reg_names = { "core-vdda" },
+ .num_regs = 1,
+
+ .power_on = qcom_hdmi_msm8x60_phy_power_on,
+ .power_off = qcom_hdmi_msm8x60_phy_power_off,
+
+ /* FIXME: no PLL support */
+};
diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c
new file mode 100644
index 000000000000..de188f660da7
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ */
+
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#include "phy-qcom-hdmi-preqmp.h"
+
+static int qcom_hdmi_preqmp_phy_init(struct phy *phy)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ return pm_runtime_resume_and_get(hdmi_phy->dev);
+}
+
+static int qcom_hdmi_preqmp_phy_exit(struct phy *phy)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ pm_runtime_put_noidle(hdmi_phy->dev);
+
+ return 0;
+}
+
+static int qcom_hdmi_preqmp_phy_power_on(struct phy *phy)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ return hdmi_phy->power_on(hdmi_phy);
+};
+
+static int qcom_hdmi_preqmp_phy_power_off(struct phy *phy)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ return hdmi_phy->power_off(hdmi_phy);
+};
+
+static int qcom_hdmi_preqmp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ const struct phy_configure_opts_hdmi *hdmi_opts = &opts->hdmi;
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = phy_get_drvdata(phy);
+ int ret = 0;
+
+ memcpy(&hdmi_phy->hdmi_opts, hdmi_opts, sizeof(*hdmi_opts));
+
+ return ret;
+}
+
+static int __maybe_unused qcom_hdmi_preqmp_runtime_resume(struct device *dev)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_bulk_enable(hdmi_phy->num_regs, hdmi_phy->regs);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare_enable(hdmi_phy->num_clks, hdmi_phy->clks);
+ if (ret)
+ goto out_disable_supplies;
+
+ return 0;
+
+out_disable_supplies:
+ regulator_bulk_disable(hdmi_phy->num_regs, hdmi_phy->regs);
+
+ return ret;
+}
+
+static int __maybe_unused qcom_hdmi_preqmp_runtime_suspend(struct device *dev)
+{
+ struct qcom_hdmi_preqmp_phy *hdmi_phy = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(hdmi_phy->num_clks, hdmi_phy->clks);
+ regulator_bulk_disable(hdmi_phy->num_regs, hdmi_phy->regs);
+
+ return 0;
+}
+
+static const struct phy_ops qcom_hdmi_preqmp_phy_ops = {
+ .init = qcom_hdmi_preqmp_phy_init,
+ .configure = qcom_hdmi_preqmp_phy_configure,
+ .power_on = qcom_hdmi_preqmp_phy_power_on,
+ .power_off = qcom_hdmi_preqmp_phy_power_off,
+ .exit = qcom_hdmi_preqmp_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int qcom_hdmi_preqmp_probe(struct platform_device *pdev)
+{
+ struct clk_init_data init;
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct qcom_hdmi_preqmp_phy *hdmi_phy;
+ const struct qcom_hdmi_preqmp_cfg *cfg;
+ int i, ret;
+
+ cfg = of_device_get_match_data(dev);
+ if (!cfg)
+ return -EINVAL;
+
+ hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
+ if (!hdmi_phy)
+ return -ENOMEM;
+
+ hdmi_phy->dev = dev;
+
+ hdmi_phy->phy_reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(hdmi_phy->phy_reg))
+ return PTR_ERR(hdmi_phy->phy_reg);
+
+ hdmi_phy->pll_reg = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(hdmi_phy->pll_reg))
+ return PTR_ERR(hdmi_phy->pll_reg);
+
+ hdmi_phy->num_clks = cfg->num_clks;
+ for (i = 0; i < cfg->num_clks; i++)
+ hdmi_phy->clks[i].id = cfg->clk_names[i];
+ ret = devm_clk_bulk_get(dev, hdmi_phy->num_clks, hdmi_phy->clks);
+ if (ret)
+ return ret;
+
+ hdmi_phy->num_regs = cfg->num_regs;
+ for (i = 0; i < cfg->num_regs; i++) {
+ hdmi_phy->regs[i].supply = cfg->reg_names[i];
+ hdmi_phy->regs[i].init_load_uA = cfg->reg_init_load[i];
+ }
+ ret = devm_regulator_bulk_get(dev, hdmi_phy->num_regs, hdmi_phy->regs);
+ if (ret)
+ return ret;
+
+ hdmi_phy->power_on = cfg->power_on;
+ hdmi_phy->power_off = cfg->power_off;
+
+ platform_set_drvdata(pdev, hdmi_phy);
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ return ret;
+
+ /* FIXME: msm8x60 doesn't yet have PLL ops */
+ if (cfg->pll_ops) {
+ init.name = "hdmipll";
+ init.ops = cfg->pll_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_data = cfg->pll_parent;
+ init.num_parents = 1;
+
+ hdmi_phy->pll_hw.init = &init;
+ ret = devm_clk_hw_register(hdmi_phy->dev, &hdmi_phy->pll_hw);
+ if (ret)
+ goto err;
+
+ ret = devm_of_clk_add_hw_provider(hdmi_phy->dev, of_clk_hw_simple_get,
+ &hdmi_phy->pll_hw);
+ if (ret)
+ goto err;
+ }
+
+ hdmi_phy->phy = devm_phy_create(dev, pdev->dev.of_node, &qcom_hdmi_preqmp_phy_ops);
+ if (IS_ERR(hdmi_phy->phy)) {
+ ret = PTR_ERR(hdmi_phy->phy);
+ goto err;
+ }
+
+ phy_set_drvdata(hdmi_phy->phy, hdmi_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ pm_runtime_put_noidle(&pdev->dev);
+ return PTR_ERR_OR_ZERO(phy_provider);
+
+err:
+ pm_runtime_put_noidle(&pdev->dev);
+ return ret;
+}
+
+static const struct of_device_id qcom_hdmi_preqmp_of_match_table[] = {
+ { .compatible = "qcom,hdmi-phy-8660", .data = &msm8x60_hdmi_phy_cfg, },
+ { .compatible = "qcom,hdmi-phy-8960", .data = &msm8960_hdmi_phy_cfg, },
+ { .compatible = "qcom,hdmi-phy-8974", .data = &msm8974_hdmi_phy_cfg, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qcom_hdmi_preqmp_of_match_table);
+
+DEFINE_RUNTIME_DEV_PM_OPS(qcom_hdmi_preqmp_pm_ops,
+ qcom_hdmi_preqmp_runtime_suspend,
+ qcom_hdmi_preqmp_runtime_resume,
+ NULL);
+
+static struct platform_driver qcom_hdmi_preqmp_driver = {
+ .probe = qcom_hdmi_preqmp_probe,
+ .driver = {
+ .name = "qcom-preqmp-hdmi-phy",
+ .of_match_table = qcom_hdmi_preqmp_of_match_table,
+ .pm = &qcom_hdmi_preqmp_pm_ops,
+ },
+};
+
+module_platform_driver(qcom_hdmi_preqmp_driver);
+
+MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm MSMpreqmp HDMI PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h
new file mode 100644
index 000000000000..dda230616d76
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ */
+
+#ifndef PHY_QCOM_HDMI_PREQMP_H
+#define PHY_QCOM_HDMI_PREQMP_H
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/phy/phy-hdmi.h>
+#include <linux/regulator/consumer.h>
+
+#define MAX_CLKS 2
+#define MAX_SUPPLIES 2
+
+struct qcom_hdmi_preqmp_phy {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *pll_reg;
+ void __iomem *phy_reg;
+
+ struct phy_configure_opts_hdmi hdmi_opts;
+
+ struct clk_hw pll_hw;
+ struct clk_bulk_data clks[MAX_CLKS];
+ int num_clks;
+
+ struct regulator_bulk_data regs[MAX_SUPPLIES];
+ int num_regs;
+
+ int (*power_on)(struct qcom_hdmi_preqmp_phy *phy);
+ int (*power_off)(struct qcom_hdmi_preqmp_phy *phy);
+};
+
+#define hw_clk_to_phy(x) container_of(x, struct qcom_hdmi_preqmp_phy, pll_hw)
+
+struct qcom_hdmi_preqmp_cfg {
+ const char * const clk_names[MAX_CLKS];
+ int num_clks;
+
+ const char * const reg_names[MAX_SUPPLIES];
+ int reg_init_load[MAX_SUPPLIES];
+ int num_regs;
+
+ int (*power_on)(struct qcom_hdmi_preqmp_phy *phy);
+ int (*power_off)(struct qcom_hdmi_preqmp_phy *phy);
+
+ const struct clk_ops *pll_ops;
+ const struct clk_parent_data *pll_parent;
+};
+
+extern const struct qcom_hdmi_preqmp_cfg msm8x60_hdmi_phy_cfg;
+extern const struct qcom_hdmi_preqmp_cfg msm8960_hdmi_phy_cfg;
+extern const struct qcom_hdmi_preqmp_cfg msm8974_hdmi_phy_cfg;
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c
new file mode 100644
index 000000000000..caca753d50e4
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ */
+
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#include "phy-qcom-qmp-hdmi.h"
+
+int qmp_hdmi_phy_init(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ return pm_runtime_resume_and_get(hdmi_phy->dev);
+}
+
+int qmp_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ const struct phy_configure_opts_hdmi *hdmi_opts = &opts->hdmi;
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+ int ret = 0;
+
+ memcpy(&hdmi_phy->hdmi_opts, hdmi_opts, sizeof(*hdmi_opts));
+
+ return ret;
+}
+
+int qmp_hdmi_phy_exit(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ pm_runtime_put_noidle(hdmi_phy->dev);
+
+ return 0;
+}
+
+static int __maybe_unused qmp_hdmi_runtime_resume(struct device *dev)
+{
+ struct qmp_hdmi_phy *hdmi_phy = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->supplies);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(hdmi_phy->clks), hdmi_phy->clks);
+ if (ret)
+ goto out_disable_supplies;
+
+ return 0;
+
+out_disable_supplies:
+ regulator_bulk_disable(ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->supplies);
+
+ return ret;
+}
+
+static int __maybe_unused qmp_hdmi_runtime_suspend(struct device *dev)
+{
+ struct qmp_hdmi_phy *hdmi_phy = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(ARRAY_SIZE(hdmi_phy->clks), hdmi_phy->clks);
+ regulator_bulk_disable(ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->supplies);
+
+ return 0;
+}
+
+static int qmp_hdmi_probe(struct platform_device *pdev)
+{
+ struct clk_init_data init = {
+ .name = "hdmipll",
+ .parent_data = (const struct clk_parent_data[]) {
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .flags = CLK_GET_RATE_NOCACHE,
+ .num_parents = 1,
+ };
+ const struct qmp_hdmi_cfg *cfg = of_device_get_match_data(&pdev->dev);
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct qmp_hdmi_phy *hdmi_phy;
+ int ret, i;
+
+ hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
+ if (!hdmi_phy)
+ return -ENOMEM;
+
+ hdmi_phy->dev = dev;
+
+ hdmi_phy->serdes = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(hdmi_phy->serdes))
+ return PTR_ERR(hdmi_phy->serdes);
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_phy->tx[i] = devm_platform_ioremap_resource(pdev, 1 + i);
+ if (IS_ERR(hdmi_phy->tx[i]))
+ return PTR_ERR(hdmi_phy->tx[i]);
+ }
+
+ hdmi_phy->phy_reg = devm_platform_ioremap_resource(pdev, 5);
+ if (IS_ERR(hdmi_phy->phy_reg))
+ return PTR_ERR(hdmi_phy->phy_reg);
+
+ hdmi_phy->clks[0].id = "iface";
+ hdmi_phy->clks[1].id = "ref";
+ ret = devm_clk_bulk_get(dev, ARRAY_SIZE(hdmi_phy->clks), hdmi_phy->clks);
+ if (ret)
+ return ret;
+
+ hdmi_phy->supplies[0].supply = "vddio";
+ hdmi_phy->supplies[0].init_load_uA = 100000;
+ hdmi_phy->supplies[1].supply = "vcca";
+ hdmi_phy->supplies[1].init_load_uA = 10000;
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->supplies);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, hdmi_phy);
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ return ret;
+
+ init.ops = cfg->pll_ops;
+ hdmi_phy->pll_hw.init = &init;
+ ret = devm_clk_hw_register(hdmi_phy->dev, &hdmi_phy->pll_hw);
+ if (ret)
+ goto err;
+
+ ret = devm_of_clk_add_hw_provider(hdmi_phy->dev, of_clk_hw_simple_get, &hdmi_phy->pll_hw);
+ if (ret)
+ goto err;
+
+ hdmi_phy->phy = devm_phy_create(dev, pdev->dev.of_node, cfg->phy_ops);
+ if (IS_ERR(hdmi_phy->phy)) {
+ ret = PTR_ERR(hdmi_phy->phy);
+ goto err;
+ }
+
+ phy_set_drvdata(hdmi_phy->phy, hdmi_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ pm_runtime_put_noidle(&pdev->dev);
+ return PTR_ERR_OR_ZERO(phy_provider);
+
+err:
+ pm_runtime_put_noidle(&pdev->dev);
+ return ret;
+}
+
+static const struct of_device_id qmp_hdmi_of_match_table[] = {
+ {
+ .compatible = "qcom,hdmi-phy-8996", .data = &qmp_hdmi_8996_cfg,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qmp_hdmi_of_match_table);
+
+DEFINE_RUNTIME_DEV_PM_OPS(qmp_hdmi_pm_ops,
+ qmp_hdmi_runtime_suspend,
+ qmp_hdmi_runtime_resume,
+ NULL);
+
+static struct platform_driver qmp_hdmi_driver = {
+ .probe = qmp_hdmi_probe,
+ .driver = {
+ .name = "qcom-qmp-hdmi-phy",
+ .of_match_table = qmp_hdmi_of_match_table,
+ .pm = &qmp_hdmi_pm_ops,
+ },
+};
+
+module_platform_driver(qmp_hdmi_driver);
+
+MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QMP HDMI PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c
new file mode 100644
index 000000000000..4f31b6c72c35
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ */
+
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/phy/phy.h>
+
+#include "phy-qcom-qmp-hdmi.h"
+#include "phy-qcom-qmp-qserdes-com.h"
+#include "phy-qcom-qmp-qserdes-txrx.h"
+
+#define HDMI_VCO_MAX_FREQ 12000000000UL
+#define HDMI_VCO_MIN_FREQ 8000000000UL
+
+#define HDMI_PCLK_MAX_FREQ 600000000UL
+#define HDMI_PCLK_MIN_FREQ 25000000UL
+
+#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL
+#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL
+#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL
+#define HDMI_DEFAULT_REF_CLOCK 19200000
+#define HDMI_PLL_CMP_CNT 1024
+
+#define HDMI_PLL_POLL_MAX_READS 100
+#define HDMI_PLL_POLL_TIMEOUT_US 150
+
+#define HDMI_8996_PHY_CFG 0x00000000
+#define HDMI_8996_PHY_PD_CTL 0x00000004
+#define HDMI_8996_PHY_MODE 0x00000008
+#define HDMI_8996_PHY_MISR_CLEAR 0x0000000c
+#define HDMI_8996_PHY_TX0_TX1_BIST_CFG0 0x00000010
+#define HDMI_8996_PHY_TX0_TX1_BIST_CFG1 0x00000014
+#define HDMI_8996_PHY_TX0_TX1_PRBS_SEED_BYTE0 0x00000018
+#define HDMI_8996_PHY_TX0_TX1_PRBS_SEED_BYTE1 0x0000001c
+#define HDMI_8996_PHY_TX0_TX1_BIST_PATTERN0 0x00000020
+#define HDMI_8996_PHY_TX0_TX1_BIST_PATTERN1 0x00000024
+#define HDMI_8996_PHY_TX2_TX3_BIST_CFG0 0x00000028
+#define HDMI_8996_PHY_TX2_TX3_BIST_CFG1 0x0000002c
+#define HDMI_8996_PHY_TX2_TX3_PRBS_SEED_BYTE0 0x00000030
+#define HDMI_8996_PHY_TX2_TX3_PRBS_SEED_BYTE1 0x00000034
+#define HDMI_8996_PHY_TX2_TX3_BIST_PATTERN0 0x00000038
+#define HDMI_8996_PHY_TX2_TX3_BIST_PATTERN1 0x0000003c
+#define HDMI_8996_PHY_DEBUG_BUS_SEL 0x00000040
+#define HDMI_8996_PHY_TXCAL_CFG0 0x00000044
+#define HDMI_8996_PHY_TXCAL_CFG1 0x00000048
+#define HDMI_8996_PHY_TX0_TX1_LANE_CTL 0x0000004c
+#define HDMI_8996_PHY_TX2_TX3_LANE_CTL 0x00000050
+#define HDMI_8996_PHY_LANE_BIST_CONFIG 0x00000054
+#define HDMI_8996_PHY_CLOCK 0x00000058
+#define HDMI_8996_PHY_MISC1 0x0000005c
+#define HDMI_8996_PHY_MISC2 0x00000060
+#define HDMI_8996_PHY_TX0_TX1_BIST_STATUS0 0x00000064
+#define HDMI_8996_PHY_TX0_TX1_BIST_STATUS1 0x00000068
+#define HDMI_8996_PHY_TX0_TX1_BIST_STATUS2 0x0000006c
+#define HDMI_8996_PHY_TX2_TX3_BIST_STATUS0 0x00000070
+#define HDMI_8996_PHY_TX2_TX3_BIST_STATUS1 0x00000074
+#define HDMI_8996_PHY_TX2_TX3_BIST_STATUS2 0x00000078
+#define HDMI_8996_PHY_PRE_MISR_STATUS0 0x0000007c
+#define HDMI_8996_PHY_PRE_MISR_STATUS1 0x00000080
+#define HDMI_8996_PHY_PRE_MISR_STATUS2 0x00000084
+#define HDMI_8996_PHY_PRE_MISR_STATUS3 0x00000088
+#define HDMI_8996_PHY_POST_MISR_STATUS0 0x0000008c
+#define HDMI_8996_PHY_POST_MISR_STATUS1 0x00000090
+#define HDMI_8996_PHY_POST_MISR_STATUS2 0x00000094
+#define HDMI_8996_PHY_POST_MISR_STATUS3 0x00000098
+#define HDMI_8996_PHY_STATUS 0x0000009c
+#define HDMI_8996_PHY_MISC3_STATUS 0x000000a0
+#define HDMI_8996_PHY_MISC4_STATUS 0x000000a4
+#define HDMI_8996_PHY_DEBUG_BUS0 0x000000a8
+#define HDMI_8996_PHY_DEBUG_BUS1 0x000000ac
+#define HDMI_8996_PHY_DEBUG_BUS2 0x000000b0
+#define HDMI_8996_PHY_DEBUG_BUS3 0x000000b4
+#define HDMI_8996_PHY_PHY_REVISION_ID0 0x000000b8
+#define HDMI_8996_PHY_PHY_REVISION_ID1 0x000000bc
+#define HDMI_8996_PHY_PHY_REVISION_ID2 0x000000c0
+#define HDMI_8996_PHY_PHY_REVISION_ID3 0x000000c4
+
+struct qmp_hdmi_8996_post_divider {
+ u64 vco_freq;
+ int hsclk_divsel;
+ int vco_ratio;
+ int tx_band_sel;
+};
+
+static inline void write16(u16 val, void __iomem *reg)
+{
+ writel(val & 0xff, reg);
+ writel(val >> 8, reg + 4);
+}
+
+static inline void write24(u32 val, void __iomem *reg)
+{
+ writel(val & 0xff, reg);
+ writel((val >> 8) & 0xff, reg + 4);
+ writel(val >> 16, reg + 8);
+}
+
+static inline u32 read24(void __iomem *reg)
+{
+ u32 val = readl(reg);
+
+ val |= readl(reg + 4) << 8;
+ val |= readl(reg + 8) << 16;
+
+ return val;
+}
+
+static inline u32 qmp_hdmi_8996_pll_get_pll_cmp(u64 fdata, unsigned long ref_clk)
+{
+ u64 dividend = HDMI_PLL_CMP_CNT * fdata;
+ u32 divisor = ref_clk * 10;
+ u32 rem;
+
+ rem = do_div(dividend, divisor);
+ if (rem > (divisor >> 1))
+ dividend++;
+
+ return dividend - 1;
+}
+
+static int qmp_hdmi_8996_pll_get_post_div(struct qmp_hdmi_8996_post_divider *pd, u64 bclk)
+{
+ int ratio[] = { 2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35 };
+ int hs_divsel[] = { 0, 4, 8, 12, 1, 5, 2, 9, 3, 13, 10, 7, 14, 11, 15 };
+ int tx_band_sel[] = { 0, 1, 2, 3 };
+ u64 vco_freq[60];
+ u64 vco, vco_optimal;
+ int half_rate_mode = 0;
+ int vco_optimal_index, vco_freq_index;
+ int i, j;
+
+retry:
+ vco_optimal = HDMI_VCO_MAX_FREQ;
+ vco_optimal_index = -1;
+ vco_freq_index = 0;
+ for (i = 0; i < 15; i++) {
+ for (j = 0; j < 4; j++) {
+ u32 ratio_mult = ratio[i] << tx_band_sel[j];
+
+ vco = bclk >> half_rate_mode;
+ vco *= ratio_mult;
+ vco_freq[vco_freq_index++] = vco;
+ }
+ }
+
+ for (i = 0; i < 60; i++) {
+ u64 vco_tmp = vco_freq[i];
+
+ if ((vco_tmp >= HDMI_VCO_MIN_FREQ) &&
+ (vco_tmp <= vco_optimal)) {
+ vco_optimal = vco_tmp;
+ vco_optimal_index = i;
+ }
+ }
+
+ if (vco_optimal_index == -1) {
+ if (!half_rate_mode) {
+ half_rate_mode = 1;
+ goto retry;
+ }
+
+ return -EINVAL;
+ }
+
+ pd->vco_freq = vco_optimal;
+ pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4];
+ pd->vco_ratio = ratio[vco_optimal_index / 4];
+ pd->hsclk_divsel = hs_divsel[vco_optimal_index / 4];
+
+ return 0;
+}
+
+static int qmp_hdmi_8996_phy_set_rate(struct qmp_hdmi_phy *hdmi_phy)
+{
+ unsigned long parent_rate = HDMI_DEFAULT_REF_CLOCK;
+ unsigned long rate = hdmi_phy->hdmi_opts.tmds_char_rate;
+ struct qmp_hdmi_8996_post_divider pd;
+ bool gen_ssc = false;
+ u64 bclk;
+ u64 dec_start;
+ u64 frac_start;
+ u64 fdata;
+ u32 pll_divisor;
+ u32 rem;
+ u32 integloop_gain;
+ u32 pll_cmp;
+ int i, ret;
+
+ bclk = ((u64)rate) * 10;
+ ret = qmp_hdmi_8996_pll_get_post_div(&pd, bclk);
+ if (ret) {
+ dev_err(hdmi_phy->dev, "PLL calculation failed\n");
+ return ret;
+ }
+
+ dec_start = pd.vco_freq;
+ pll_divisor = 4 * parent_rate;
+ do_div(dec_start, pll_divisor);
+
+ frac_start = pd.vco_freq * (1 << 20);
+
+ rem = do_div(frac_start, pll_divisor);
+ frac_start -= dec_start * (1 << 20);
+ if (rem > (pll_divisor >> 1))
+ frac_start++;
+
+ fdata = pd.vco_freq;
+ do_div(fdata, pd.vco_ratio);
+
+ pll_cmp = qmp_hdmi_8996_pll_get_pll_cmp(fdata, parent_rate);
+
+ /* Initially shut down PHY */
+ dev_dbg(hdmi_phy->dev, "Disabling PHY");
+ writel(0x0, hdmi_phy->phy_reg + HDMI_8996_PHY_PD_CTL);
+ udelay(500);
+
+ /* Power up sequence */
+ writel(0x04, hdmi_phy->serdes + QSERDES_COM_BG_CTRL);
+
+ writel(0x1, hdmi_phy->phy_reg + HDMI_8996_PHY_PD_CTL);
+ writel(0x20, hdmi_phy->serdes + QSERDES_COM_RESETSM_CNTRL);
+ writel(0x0f, hdmi_phy->phy_reg + HDMI_8996_PHY_TX0_TX1_LANE_CTL);
+ writel(0x0f, hdmi_phy->phy_reg + HDMI_8996_PHY_TX2_TX3_LANE_CTL);
+
+ writel(0x43, hdmi_phy->tx[0] + QSERDES_TX_LANE_MODE);
+ writel(0x43, hdmi_phy->tx[2] + QSERDES_TX_LANE_MODE);
+
+ writel(0x1e, hdmi_phy->serdes + QSERDES_COM_SYSCLK_BUF_ENABLE);
+ writel(0x07, hdmi_phy->serdes + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
+ writel(0x37, hdmi_phy->serdes + QSERDES_COM_SYSCLK_EN_SEL);
+ writel(0x02, hdmi_phy->serdes + QSERDES_COM_SYS_CLK_CTRL);
+ writel(0x0e, hdmi_phy->serdes + QSERDES_COM_CLK_ENABLE1);
+
+ if (frac_start != 0 || gen_ssc) {
+ writel(0x28, hdmi_phy->serdes + QSERDES_COM_PLL_CCTRL_MODE0);
+ writel(0x16, hdmi_phy->serdes + QSERDES_COM_PLL_RCTRL_MODE0);
+ writel(11000000 / (parent_rate / 20),
+ hdmi_phy + QSERDES_COM_CP_CTRL_MODE0);
+ integloop_gain = (64 * parent_rate) / HDMI_DEFAULT_REF_CLOCK;
+ } else {
+ writel(0x01, hdmi_phy->serdes + QSERDES_COM_PLL_CCTRL_MODE0);
+ writel(0x10, hdmi_phy->serdes + QSERDES_COM_PLL_RCTRL_MODE0);
+ writel(0x23, hdmi_phy->serdes + QSERDES_COM_CP_CTRL_MODE0);
+ integloop_gain = (1022 * parent_rate) / (100 * 1000 * 1000);
+ }
+
+ /* Bypass VCO calibration */
+ if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
+ writel(1, hdmi_phy->serdes + QSERDES_COM_SVS_MODE_CLK_SEL);
+ integloop_gain <<= 1;
+ } else {
+ writel(2, hdmi_phy->serdes + QSERDES_COM_SVS_MODE_CLK_SEL);
+ integloop_gain <<= 2;
+ }
+
+ integloop_gain = min_t(u32, integloop_gain, 2046);
+
+ writel(0x0f, hdmi_phy->serdes + QSERDES_COM_BG_TRIM);
+ writel(0x0f, hdmi_phy->serdes + QSERDES_COM_PLL_IVCO);
+ writel(0, hdmi_phy->serdes + QSERDES_COM_VCO_TUNE_CTRL);
+
+ writel(0x06, hdmi_phy->serdes + QSERDES_COM_BG_CTRL);
+
+ writel(0x30, hdmi_phy->serdes + QSERDES_COM_CLK_SELECT);
+ writel(0x20 | pd.hsclk_divsel, hdmi_phy->serdes + QSERDES_COM_HSCLK_SEL);
+ writel(0x0, hdmi_phy->serdes + QSERDES_COM_LOCK_CMP_EN);
+
+ writel(dec_start, hdmi_phy->serdes + QSERDES_COM_DEC_START_MODE0);
+ write24(frac_start, hdmi_phy->serdes + QSERDES_COM_DIV_FRAC_START1_MODE0);
+
+ write16(integloop_gain, hdmi_phy->serdes + QSERDES_COM_INTEGLOOP_GAIN0_MODE0);
+
+ write24(pll_cmp, hdmi_phy->serdes + QSERDES_COM_LOCK_CMP1_MODE0);
+
+ writel(0x00, hdmi_phy->serdes + QSERDES_COM_VCO_TUNE_MAP);
+ writel(0x2c, hdmi_phy->serdes + QSERDES_COM_CORE_CLK_EN);
+ writel(5, hdmi_phy->serdes + QSERDES_COM_CORECLK_DIV);
+ writel(0x02, hdmi_phy->serdes + QSERDES_COM_CMN_CONFIG);
+
+ writel(0x15, hdmi_phy->serdes + QSERDES_COM_RESCODE_DIV_NUM);
+
+ /* TX lanes setup (TX 0/1/2/3) */
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(0x03, hdmi_phy->tx[i] + QSERDES_TX_CLKBUF_ENABLE);
+ writel(pd.tx_band_sel + 4, hdmi_phy->tx[i] + QSERDES_TX_TX_BAND);
+ writel(0x03, hdmi_phy->tx[i] + QSERDES_TX_RESET_TSYNC_EN);
+ writel(0x00, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL1);
+ writel(0x00, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL_OFFSET);
+ writel(0x00, hdmi_phy->tx[i] + QSERDES_TX_RES_CODE_LANE_OFFSET);
+ writel(0x03, hdmi_phy->tx[i] + QSERDES_TX_TRAN_DRVR_EMP_EN);
+ writel(0x40, hdmi_phy->tx[i] + QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN);
+ writel(i != 3 ? 0xc : 0x3, hdmi_phy->tx[i] + QSERDES_TX_HP_PD_ENABLES);
+ }
+
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(i != 3 ? 0x25 : 0x22, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL);
+ writel(i != 3 ? 0x23 : 0x27, hdmi_phy->tx[i] + QSERDES_TX_TX_EMP_POST1_LVL);
+ writel(i != 3 ? 0x0d : 0x00, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL2);
+ }
+ } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(0x25, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL);
+ writel(0x23, hdmi_phy->tx[i] + QSERDES_TX_TX_EMP_POST1_LVL);
+ writel(i != 3 ? 0x0d : 0x00, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL2);
+ }
+ } else {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(0x20, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL);
+ writel(0x20, hdmi_phy->tx[i] + QSERDES_TX_TX_EMP_POST1_LVL);
+ writel(0x0e, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL2);
+ }
+ }
+
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+ writel(0x10, hdmi_phy->phy_reg + HDMI_8996_PHY_MODE);
+ else
+ writel(0x00, hdmi_phy->phy_reg + HDMI_8996_PHY_MODE);
+ writel(0x1f, hdmi_phy->phy_reg + HDMI_8996_PHY_PD_CTL);
+
+ return 0;
+}
+
+static int qmp_hdmi_8996_phy_power_on(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+ u32 status;
+ int i, ret = 0;
+
+ ret = qmp_hdmi_8996_phy_set_rate(hdmi_phy);
+ if (ret) {
+ dev_err(hdmi_phy->dev, "Setting pixel clock rate failed\n");
+ return ret;
+ }
+
+ writel(0x1, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG);
+ udelay(100);
+
+ writel(0x19, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG);
+ udelay(100);
+
+ ret = readl_poll_timeout(hdmi_phy->serdes + QSERDES_COM_C_READY_STATUS,
+ status, status & BIT(0),
+ HDMI_PLL_POLL_TIMEOUT_US,
+ HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US);
+
+ if (ret) {
+ dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n");
+ return ret;
+ }
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)
+ writel(0x6f, hdmi_phy->tx[i] + QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+
+ /* Disable SSC */
+ writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_PER1);
+ writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_PER2);
+ writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_STEP_SIZE1);
+ writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_STEP_SIZE2);
+ writel(0x2, hdmi_phy->serdes + QSERDES_COM_SSC_EN_CENTER);
+
+ ret = readl_poll_timeout(hdmi_phy->phy_reg + HDMI_8996_PHY_STATUS,
+ status, status & BIT(0),
+ HDMI_PLL_POLL_TIMEOUT_US,
+ HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n");
+ return ret;
+ }
+
+ /* Restart the retiming buffer */
+ writel(0x18, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG);
+ udelay(1);
+ writel(0x19, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG);
+
+ return 0;
+}
+
+static int qmp_hdmi_8996_phy_power_off(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ writel(0x6, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG);
+ usleep_range(100, 150);
+
+ return 0;
+}
+
+static int qmp_hdmi_8996_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ req->rate = clamp(req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ);
+
+ return 0;
+}
+
+static unsigned long qmp_hdmi_8996_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct qmp_hdmi_phy *phy = hw_clk_to_pll(hw);
+ u32 pll_cmp = read24(phy->serdes + QSERDES_COM_LOCK_CMP1_MODE0);
+
+ return mult_frac(pll_cmp + 1, parent_rate, HDMI_PLL_CMP_CNT);
+}
+
+static int qmp_hdmi_8996_pll_is_enabled(struct clk_hw *hw)
+{
+ struct qmp_hdmi_phy *phy = hw_clk_to_pll(hw);
+ u32 status;
+ int pll_locked;
+
+ status = readl(phy->serdes + QSERDES_COM_C_READY_STATUS);
+ pll_locked = status & BIT(0);
+
+ return pll_locked;
+}
+
+static const struct clk_ops qmp_hdmi_8996_pll_ops = {
+ .recalc_rate = qmp_hdmi_8996_pll_recalc_rate,
+ .determine_rate = qmp_hdmi_8996_pll_determine_rate,
+ .is_enabled = qmp_hdmi_8996_pll_is_enabled,
+};
+
+static const struct phy_ops qmp_hdmi_8996_phy_ops = {
+ .init = qmp_hdmi_phy_init,
+ .configure = qmp_hdmi_phy_configure,
+ .power_on = qmp_hdmi_8996_phy_power_on,
+ .power_off = qmp_hdmi_8996_phy_power_off,
+ .exit = qmp_hdmi_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+const struct qmp_hdmi_cfg qmp_hdmi_8996_cfg = {
+ .pll_ops = &qmp_hdmi_8996_pll_ops,
+ .phy_ops = &qmp_hdmi_8996_phy_ops,
+};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c
new file mode 100644
index 000000000000..495c5ee053d6
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c
@@ -0,0 +1,489 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Freebox SAS
+ * Copyright (c) 2025, Qualcomm Incorporated
+ */
+
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/phy/phy.h>
+#include <linux/units.h>
+
+#include "phy-qcom-qmp-hdmi.h"
+#include "phy-qcom-qmp-qserdes-com-v3.h"
+#include "phy-qcom-qmp-qserdes-txrx.h"
+
+#define HDMI_VCO_MAX_FREQ 12000000000UL
+#define HDMI_VCO_MIN_FREQ 8000000000UL
+
+#define HDMI_PCLK_MAX_FREQ 600000000UL
+#define HDMI_PCLK_MIN_FREQ 25000000UL
+
+#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL
+#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL
+#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL
+#define HDMI_DEFAULT_REF_CLOCK 19200000
+#define HDMI_PLL_CMP_CNT 1024
+
+#define HDMI_PLL_POLL_MAX_READS 100
+#define HDMI_PLL_POLL_TIMEOUT_US 150
+
+#define HDMI_8998_PHY_CFG 0x00000000
+#define HDMI_8998_PHY_PD_CTL 0x00000004
+#define HDMI_8998_PHY_MODE 0x00000010
+#define HDMI_8998_PHY_CLOCK 0x0000005c
+#define HDMI_8998_PHY_CMN_CTRL 0x00000068
+#define HDMI_8998_PHY_STATUS 0x000000b4
+
+#define HDMI_8998_PHY_TXn_EMP_POST1_LVL 0x00000000
+#define HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND 0x00000008
+#define HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE 0x0000000c
+#define HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET 0x00000014
+#define HDMI_8998_PHY_TXn_DRV_LVL 0x00000018
+#define HDMI_8998_PHY_TXn_LANE_CONFIG 0x0000001c
+#define HDMI_8998_PHY_TXn_PRE_DRIVER_1 0x00000024
+#define HDMI_8998_PHY_TXn_PRE_DRIVER_2 0x00000028
+#define HDMI_8998_PHY_TXn_LANE_MODE 0x0000002c
+
+struct qmp_hdmi_8998_post_divider {
+ u64 vco_freq;
+ int hsclk_divsel;
+ int vco_ratio;
+ int tx_band_sel;
+ int half_rate_mode;
+};
+
+static inline void write16(u16 val, void __iomem *reg)
+{
+ writel(val & 0xff, reg);
+ writel(val >> 8, reg + 4);
+}
+
+static inline void write24(u32 val, void __iomem *reg)
+{
+ writel(val & 0xff, reg);
+ writel((val >> 8) & 0xff, reg + 4);
+ writel(val >> 16, reg + 8);
+}
+
+static inline u32 read24(void __iomem *reg)
+{
+ u32 val = readl(reg);
+
+ val |= readl(reg + 4) << 8;
+ val |= readl(reg + 8) << 16;
+
+ return val;
+}
+
+static inline u32 qmp_hdmi_8998_pll_get_pll_cmp(u64 fdata, unsigned long ref_clk)
+{
+ u64 dividend = HDMI_PLL_CMP_CNT * fdata;
+ u32 divisor = ref_clk * 10;
+ u32 rem;
+
+ rem = do_div(dividend, divisor);
+ if (rem > (divisor >> 1))
+ dividend++;
+
+ return dividend - 1;
+}
+
+static int qmp_hdmi_8998_pll_get_post_div(struct qmp_hdmi_8998_post_divider *pd, u64 bclk)
+{
+ u32 const ratio_list[] = {1, 2, 3, 4, 5, 6, 9, 10, 12, 15, 25};
+ u32 const band_list[] = {0, 1, 2, 3};
+ u32 const sz_ratio = ARRAY_SIZE(ratio_list);
+ u32 const sz_band = ARRAY_SIZE(band_list);
+ u32 const cmp_cnt = 1024;
+ u32 const th_min = 500, th_max = 1000;
+ u32 half_rate_mode = 0;
+ u32 list_elements;
+ int optimal_index;
+ u32 i, j, k;
+ u32 found_hsclk_divsel = 0, found_vco_ratio;
+ u32 found_tx_band_sel;
+ u64 const min_freq = HDMI_VCO_MIN_FREQ, max_freq = HDMI_VCO_MAX_FREQ;
+ u64 freq_list[ARRAY_SIZE(ratio_list) * ARRAY_SIZE(band_list)];
+ u64 found_vco_freq;
+ u64 freq_optimal;
+
+find_optimal_index:
+ freq_optimal = max_freq;
+ optimal_index = -1;
+ list_elements = 0;
+
+ for (i = 0; i < sz_ratio; i++) {
+ for (j = 0; j < sz_band; j++) {
+ u64 freq = div_u64(bclk, (1 << half_rate_mode));
+
+ freq *= (ratio_list[i] * (1 << band_list[j]));
+ freq_list[list_elements++] = freq;
+ }
+ }
+
+ for (k = 0; k < ARRAY_SIZE(freq_list); k++) {
+ u32 const clks_pll_div = 2, core_clk_div = 5;
+ u32 const rng1 = 16, rng2 = 8;
+ u32 th1, th2;
+ u64 core_clk, rvar1, rem;
+
+ core_clk = div_u64(freq_list[k],
+ ratio_list[k / sz_band] * clks_pll_div *
+ core_clk_div);
+
+ rvar1 = HDMI_DEFAULT_REF_CLOCK * rng1 * HZ_PER_MHZ;
+ rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem);
+ if (rem > ((cmp_cnt * core_clk) >> 1))
+ rvar1++;
+ th1 = rvar1;
+
+ rvar1 = HDMI_DEFAULT_REF_CLOCK * rng2 * HZ_PER_MHZ;
+ rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem);
+ if (rem > ((cmp_cnt * core_clk) >> 1))
+ rvar1++;
+ th2 = rvar1;
+
+ if (freq_list[k] >= min_freq &&
+ freq_list[k] <= max_freq) {
+ if ((th1 >= th_min && th1 <= th_max) ||
+ (th2 >= th_min && th2 <= th_max)) {
+ if (freq_list[k] <= freq_optimal) {
+ freq_optimal = freq_list[k];
+ optimal_index = k;
+ }
+ }
+ }
+ }
+
+ if (optimal_index == -1) {
+ if (!half_rate_mode) {
+ half_rate_mode = 1;
+ goto find_optimal_index;
+ } else {
+ return -EINVAL;
+ }
+ } else {
+ found_vco_ratio = ratio_list[optimal_index / sz_band];
+ found_tx_band_sel = band_list[optimal_index % sz_band];
+ found_vco_freq = freq_optimal;
+ }
+
+ switch (found_vco_ratio) {
+ case 1:
+ found_hsclk_divsel = 15;
+ break;
+ case 2:
+ found_hsclk_divsel = 0;
+ break;
+ case 3:
+ found_hsclk_divsel = 4;
+ break;
+ case 4:
+ found_hsclk_divsel = 8;
+ break;
+ case 5:
+ found_hsclk_divsel = 12;
+ break;
+ case 6:
+ found_hsclk_divsel = 1;
+ break;
+ case 9:
+ found_hsclk_divsel = 5;
+ break;
+ case 10:
+ found_hsclk_divsel = 2;
+ break;
+ case 12:
+ found_hsclk_divsel = 9;
+ break;
+ case 15:
+ found_hsclk_divsel = 13;
+ break;
+ case 25:
+ found_hsclk_divsel = 14;
+ break;
+ }
+
+ pd->vco_freq = found_vco_freq;
+ pd->tx_band_sel = found_tx_band_sel;
+ pd->vco_ratio = found_vco_ratio;
+ pd->hsclk_divsel = found_hsclk_divsel;
+
+ return 0;
+}
+
+static int qmp_hdmi_8998_phy_set_rate(struct qmp_hdmi_phy *hdmi_phy)
+{
+ unsigned long parent_rate = HDMI_DEFAULT_REF_CLOCK;
+ unsigned long rate = hdmi_phy->hdmi_opts.tmds_char_rate;
+ struct qmp_hdmi_8998_post_divider pd;
+ bool gen_ssc = false;
+ u64 bclk;
+ u64 dec_start;
+ u64 frac_start;
+ u64 fdata;
+ u32 pll_divisor;
+ u32 rem;
+ u32 integloop_gain;
+ u32 pll_cmp;
+ int i, ret;
+
+ bclk = ((u64)rate) * 10;
+ ret = qmp_hdmi_8998_pll_get_post_div(&pd, bclk);
+ if (ret) {
+ dev_err(hdmi_phy->dev, "PLL calculation failed\n");
+ return ret;
+ }
+
+ dec_start = pd.vco_freq;
+ pll_divisor = 4 * parent_rate;
+ do_div(dec_start, pll_divisor);
+
+ frac_start = pd.vco_freq * (1 << 20);
+
+ rem = do_div(frac_start, pll_divisor);
+ frac_start -= dec_start * (1 << 20);
+ if (rem > (pll_divisor >> 1))
+ frac_start++;
+
+ fdata = pd.vco_freq;
+ do_div(fdata, pd.vco_ratio);
+
+ pll_cmp = qmp_hdmi_8998_pll_get_pll_cmp(fdata, parent_rate);
+
+ /* Initially shut down PHY */
+ dev_dbg(hdmi_phy->dev, "Disabling PHY");
+ writel(0x0, hdmi_phy->phy_reg + HDMI_8998_PHY_PD_CTL);
+ udelay(500);
+
+ /* Power up sequence */
+ writel(0x1, hdmi_phy->phy_reg + HDMI_8998_PHY_PD_CTL);
+ writel(0x20, hdmi_phy->serdes + QSERDES_V3_COM_RESETSM_CNTRL);
+ writel(0x6, hdmi_phy->phy_reg + HDMI_8998_PHY_CMN_CTRL);
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(pd.tx_band_sel,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND);
+ writel(0x1, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE);
+ writel(0x20, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_LANE_MODE);
+ }
+
+ writel(0x02, hdmi_phy->serdes + QSERDES_V3_COM_SYSCLK_BUF_ENABLE);
+ writel(0x0B, hdmi_phy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
+ writel(0x37, hdmi_phy->serdes + QSERDES_V3_COM_SYSCLK_EN_SEL);
+ writel(0x02, hdmi_phy->serdes + QSERDES_V3_COM_SYS_CLK_CTRL);
+ writel(0x0E, hdmi_phy->serdes + QSERDES_V3_COM_CLK_ENABLE1);
+
+ if (frac_start != 0 || gen_ssc) {
+ writel(0x34, hdmi_phy->serdes + QSERDES_V3_COM_PLL_CCTRL_MODE0);
+ writel(0x16, hdmi_phy->serdes + QSERDES_V3_COM_PLL_RCTRL_MODE0);
+ writel(0x08, hdmi_phy->serdes + QSERDES_V3_COM_CP_CTRL_MODE0);
+ integloop_gain = 0x3f;
+ } else {
+ writel(0x02, hdmi_phy->serdes + QSERDES_V3_COM_PLL_CCTRL_MODE0);
+ writel(0x18, hdmi_phy->serdes + QSERDES_V3_COM_PLL_RCTRL_MODE0);
+ writel(0x30, hdmi_phy->serdes + QSERDES_V3_COM_CP_CTRL_MODE0);
+ integloop_gain = 0xc4;
+ }
+
+ /* Bypass VCO calibration */
+ if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
+ writel(1, hdmi_phy->serdes + QSERDES_V3_COM_SVS_MODE_CLK_SEL);
+ integloop_gain <<= 1;
+ } else {
+ writel(2, hdmi_phy->serdes + QSERDES_V3_COM_SVS_MODE_CLK_SEL);
+ integloop_gain <<= 2;
+ }
+
+ writel(0x07, hdmi_phy->serdes + QSERDES_V3_COM_PLL_IVCO);
+ writel(0x00, hdmi_phy->serdes + QSERDES_V3_COM_VCO_TUNE_CTRL);
+
+ writel(0x30, hdmi_phy->serdes + QSERDES_V3_COM_CLK_SELECT);
+ writel(0x20 | pd.hsclk_divsel, hdmi_phy->serdes + QSERDES_V3_COM_HSCLK_SEL);
+ writel(0x0, hdmi_phy->serdes + QSERDES_V3_COM_LOCK_CMP_EN);
+
+ writel(dec_start, hdmi_phy->serdes + QSERDES_V3_COM_DEC_START_MODE0);
+ write24(frac_start, hdmi_phy->serdes + QSERDES_V3_COM_DIV_FRAC_START1_MODE0);
+
+ write16(integloop_gain, hdmi_phy->serdes + QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0);
+
+ write24(pll_cmp, hdmi_phy->serdes + QSERDES_V3_COM_LOCK_CMP1_MODE0);
+
+ writel(0x00, hdmi_phy->serdes + QSERDES_V3_COM_VCO_TUNE_MAP);
+ writel(0x2c, hdmi_phy->serdes + QSERDES_V3_COM_CORE_CLK_EN);
+ writel(5, hdmi_phy->serdes + QSERDES_V3_COM_CORECLK_DIV_MODE0);
+
+ /* TX lanes setup (TX 0/1/2/3) */
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(0xf,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL);
+ writel(i == 3 ? 0x00 : i == 1 ? 0x02 : 0x03,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1);
+ writel(i == 3 ? 0x00 : 0x1c,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2);
+ writel((i == 0 || i == 3) ? 0x03 : 0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET);
+ }
+ } else if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(0x0f,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL);
+ writel(i == 3 ? 0x00 : 0x03,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1);
+ writel(i == 3 ? 0x18 : 0x16,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2);
+ writel(i == 0 ? 0x03 : 0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET);
+ }
+ } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(0x0f,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL);
+ writel(i == 3 ? 0x00 : 0x05,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1);
+ writel(0x0e,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET);
+ }
+ } else {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ writel(i == 3 ? 0x00 : 0x01,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1);
+ writel(i == 3 ? 0x18 : 0x16,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2);
+ writel(0x00,
+ hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET);
+ }
+ }
+
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+ writel(0x5, hdmi_phy->phy_reg + HDMI_8998_PHY_MODE);
+ else
+ writel(0x4, hdmi_phy->phy_reg + HDMI_8998_PHY_MODE);
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)
+ writel(0x10, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_LANE_CONFIG);
+
+ return 0;
+}
+
+static int qmp_hdmi_8998_phy_power_on(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+ u32 status;
+ int i, ret = 0;
+
+ ret = qmp_hdmi_8998_phy_set_rate(hdmi_phy);
+ if (ret) {
+ dev_err(hdmi_phy->dev, "Setting pixel clock rate failed\n");
+ return ret;
+ }
+
+ writel(0x1, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG);
+ udelay(100);
+
+ writel(0x59, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG);
+ udelay(100);
+
+ ret = readl_poll_timeout(hdmi_phy->serdes + QSERDES_V3_COM_C_READY_STATUS,
+ status, status & BIT(0),
+ HDMI_PLL_POLL_TIMEOUT_US,
+ HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US);
+
+ if (ret) {
+ dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n");
+ return ret;
+ }
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)
+ writel(0x1f, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_LANE_CONFIG);
+
+ ret = readl_poll_timeout(hdmi_phy->phy_reg + HDMI_8998_PHY_STATUS,
+ status, status & BIT(0),
+ HDMI_PLL_POLL_TIMEOUT_US,
+ HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n");
+ return ret;
+ }
+
+ /* Restart the retiming buffer */
+ writel(0x58, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG);
+ udelay(1);
+ writel(0x59, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG);
+
+ return 0;
+}
+
+static int qmp_hdmi_8998_phy_power_off(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ writel(0, hdmi_phy->phy_reg + HDMI_8998_PHY_PD_CTL);
+ usleep_range(100, 150);
+
+ return 0;
+}
+
+static int qmp_hdmi_8998_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ req->rate = clamp(req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ);
+
+ return 0;
+}
+
+static unsigned long qmp_hdmi_8998_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct qmp_hdmi_phy *phy = hw_clk_to_pll(hw);
+ u32 pll_cmp = read24(phy->serdes + QSERDES_V3_COM_LOCK_CMP1_MODE0);
+
+ return mult_frac(pll_cmp + 1, parent_rate, HDMI_PLL_CMP_CNT);
+}
+
+static int qmp_hdmi_8998_pll_is_enabled(struct clk_hw *hw)
+{
+ struct qmp_hdmi_phy *phy = hw_clk_to_pll(hw);
+ u32 status;
+ int pll_locked;
+
+ status = readl(phy->serdes + QSERDES_V3_COM_C_READY_STATUS);
+ pll_locked = status & BIT(0);
+
+ return pll_locked;
+}
+
+static const struct clk_ops qmp_hdmi_8998_pll_ops = {
+ .recalc_rate = qmp_hdmi_8998_pll_recalc_rate,
+ .determine_rate = qmp_hdmi_8998_pll_determine_rate,
+ .is_enabled = qmp_hdmi_8998_pll_is_enabled,
+};
+
+static const struct phy_ops qmp_hdmi_8998_phy_ops = {
+ .init = qmp_hdmi_phy_init,
+ .configure = qmp_hdmi_phy_configure,
+ .power_on = qmp_hdmi_8998_phy_power_on,
+ .power_off = qmp_hdmi_8998_phy_power_off,
+ .exit = qmp_hdmi_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+const struct qmp_hdmi_cfg qmp_hdmi_8998_cfg = {
+ .pll_ops = &qmp_hdmi_8998_pll_ops,
+ .phy_ops = &qmp_hdmi_8998_phy_ops,
+};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h
new file mode 100644
index 000000000000..7a92ac02cab5
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ * Copyright (c) 2025, Qualcomm Incorporated
+ */
+
+#ifndef PHY_QCOM_QMP_HDMI_H
+#define PHY_QCOM_QMP_HDMI_H
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regulator/consumer.h>
+#include <linux/phy/phy-hdmi.h>
+
+#define MAX_CLKS 2
+#define MAX_SUPPLIES 2
+
+#define HDMI_NUM_TX_CHANNEL 4
+
+struct qmp_hdmi_phy {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *serdes;
+ void __iomem *tx[HDMI_NUM_TX_CHANNEL];
+ void __iomem *phy_reg;
+
+ struct phy_configure_opts_hdmi hdmi_opts;
+
+ struct clk_hw pll_hw;
+ struct clk_bulk_data clks[MAX_CLKS];
+ struct regulator_bulk_data supplies[MAX_SUPPLIES];
+};
+
+struct qmp_hdmi_cfg {
+ const struct clk_ops *pll_ops;
+ const struct phy_ops *phy_ops;
+};
+
+#define hw_clk_to_pll(x) container_of(x, struct qmp_hdmi_phy, pll_hw)
+
+int qmp_hdmi_phy_init(struct phy *phy);
+int qmp_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts);
+int qmp_hdmi_phy_exit(struct phy *phy);
+
+extern const struct qmp_hdmi_cfg qmp_hdmi_8996_cfg;
+extern const struct qmp_hdmi_cfg qmp_hdmi_8998_cfg;
+
+#endif
--
2.47.3
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 1/1] arm64: dts: qcom: hamoa: Fix incomplete Root Port property migration
From: Ziyue Zhang @ 2026-03-30 2:09 UTC (permalink / raw)
To: andersson, konradybcio, robh, krzk+dt, conor+dt, ziyue.zhang,
jingoohan1, mani, lpieralisi, kwilczynski, bhelgaas, johan+linaro,
vkoul, kishon, neil.armstrong, abel.vesa, kw
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, linux-phy,
qiang.yu, quic_krichai, quic_vbadigan
Historically, the Qualcomm PCIe controller node (Host bridge) described
all Root Port properties, such as PHY, PERST#, and WAKE#. But to provide
a more accurate hardware description and to support future multi-Root Port
controllers, these properties were moved to the Root Port node in the
devicetree bindings.
Commit 960609b22be5 ("arm64: dts: qcom: hamoa: Move PHY, PERST, and Wake
GPIOs to PCIe port nodes and add port Nodes for all PCIe ports")
initiated this transition for the Hamoa platform by moving the PHY
property to the Root Port node in hamoa.dtsi. However, it only updated
some platform specific DTS files for PERST# and WAKE#, leaving others in
a "mixed" binding state.
While the PCIe controller driver supports both legacy and Root Port
bindings, It cannot correctly handle a mix of both. In these cases, the
driver parses the PHY from the Root Port node, but fails to find the
PERST# property (which it then assumes is not present, as it is optional).
Consequently, the controller probe succeeds, but PERST# remains
uncontrolled, preventing PCIe endpoints from functioning.
So, fix the incomplete migration by moving the PERST# and WAKE# properties
from the controller node to the Root Port node in all remaining Hamoa
platform DTS files.
Fixes: 960609b22be5 ("arm64: dts: qcom: hamoa: Move PHY, PERST, and Wake GPIOs to PCIe port nodes and add port Nodes for all PCIe ports")
Signed-off-by: Ziyue Zhang <ziyue.zhang@oss.qualcomm.com>
---
.../boot/dts/qcom/x1-asus-zenbook-a14.dtsi | 16 ++++++++-----
arch/arm64/boot/dts/qcom/x1-crd.dtsi | 24 ++++++++++++-------
arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 14 ++++++-----
.../boot/dts/qcom/x1-hp-omnibook-x14.dtsi | 14 ++++++-----
.../boot/dts/qcom/x1-microsoft-denali.dtsi | 8 ++++---
.../dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 6 ++---
.../qcom/x1e80100-medion-sprchrgd-14-s1.dts | 14 +++++------
.../dts/qcom/x1p42100-lenovo-thinkbook-16.dts | 14 ++++++-----
8 files changed, 64 insertions(+), 46 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
index cd062f844b2d..66d566808f58 100644
--- a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
@@ -1079,9 +1079,6 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
@@ -1095,10 +1092,12 @@ &pcie4_phy {
status = "okay";
};
-&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+};
+&pcie6a {
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-0 = <&pcie6a_default>;
@@ -1114,6 +1113,11 @@ &pcie6a_phy {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pm8550_gpios {
rtmr0_default: rtmr0-reset-n-active-state {
pins = "gpio10";
diff --git a/arch/arm64/boot/dts/qcom/x1-crd.dtsi b/arch/arm64/boot/dts/qcom/x1-crd.dtsi
index 485dcd946757..a9c5c523575e 100644
--- a/arch/arm64/boot/dts/qcom/x1-crd.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1-crd.dtsi
@@ -1248,15 +1248,17 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
status = "okay";
};
+&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+};
+
&pcie4_phy {
vdda-phy-supply = <&vreg_l3i_0p8>;
vdda-pll-supply = <&vreg_l3e_1p2>;
@@ -1265,9 +1267,6 @@ &pcie4_phy {
};
&pcie5 {
- perst-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>;
-
vddpe-3v3-supply = <&vreg_wwan>;
pinctrl-0 = <&pcie5_default>;
@@ -1283,10 +1282,12 @@ &pcie5_phy {
status = "okay";
};
-&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+&pcie5_port0 {
+ reset-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>;
+};
+&pcie6a {
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-names = "default";
@@ -1302,6 +1303,11 @@ &pcie6a_phy {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pm8550_gpios {
kypd_vol_up_n: kypd-vol-up-n-state {
pins = "gpio6";
diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
index 343844cc62f2..0d9a324cc6cc 100644
--- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
@@ -1081,9 +1081,6 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
@@ -1098,6 +1095,9 @@ &pcie4_phy {
};
&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
wifi@0 {
compatible = "pci17cb,1107";
reg = <0x10000 0x0 0x0 0x0 0x0>;
@@ -1115,9 +1115,6 @@ wifi@0 {
};
&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
-
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-0 = <&pcie6a_default>;
@@ -1126,6 +1123,11 @@ &pcie6a {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pcie6a_phy {
vdda-phy-supply = <&vreg_l1d_0p8>;
vdda-pll-supply = <&vreg_l2j_1p2>;
diff --git a/arch/arm64/boot/dts/qcom/x1-hp-omnibook-x14.dtsi b/arch/arm64/boot/dts/qcom/x1-hp-omnibook-x14.dtsi
index 16437139d336..b773a4976d1b 100644
--- a/arch/arm64/boot/dts/qcom/x1-hp-omnibook-x14.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1-hp-omnibook-x14.dtsi
@@ -1065,9 +1065,6 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
@@ -1082,6 +1079,9 @@ &pcie4_phy {
};
&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
wifi@0 {
compatible = "pci17cb,1107";
reg = <0x10000 0x0 0x0 0x0 0x0>;
@@ -1099,9 +1099,6 @@ wifi@0 {
};
&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
-
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-0 = <&pcie6a_default>;
@@ -1110,6 +1107,11 @@ &pcie6a {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pcie6a_phy {
vdda-phy-supply = <&vreg_l1d_0p8>;
vdda-pll-supply = <&vreg_l2j_1p2>;
diff --git a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi
index 6ab595b6ea30..dd2de1f723b0 100644
--- a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi
@@ -964,9 +964,6 @@ wifi@0 {
};
&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
-
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-0 = <&pcie6a_default>;
@@ -982,6 +979,11 @@ &pcie6a_phy {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pm8550_gpios {
rtmr0_default: rtmr0-reset-n-active-state {
pins = "gpio10";
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
index bd0e3009fb41..beb1475d7fa0 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
+++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
@@ -1126,9 +1126,6 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
@@ -1143,6 +1140,9 @@ &pcie4_phy {
};
&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
wifi@0 {
compatible = "pci17cb,1107";
reg = <0x10000 0x0 0x0 0x0 0x0>;
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-medion-sprchrgd-14-s1.dts b/arch/arm64/boot/dts/qcom/x1e80100-medion-sprchrgd-14-s1.dts
index 763efb9e070d..23a298248a29 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-medion-sprchrgd-14-s1.dts
+++ b/arch/arm64/boot/dts/qcom/x1e80100-medion-sprchrgd-14-s1.dts
@@ -1033,9 +1033,6 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
@@ -1050,6 +1047,8 @@ &pcie4_phy {
};
&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
wifi@0 {
compatible = "pci17cb,1107";
reg = <0x10000 0x0 0x0 0x0 0x0>;
@@ -1067,10 +1066,6 @@ wifi@0 {
};
&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
-
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
-
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-0 = <&pcie6a_default>;
@@ -1086,6 +1081,11 @@ &pcie6a_phy {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pm8550_gpios {
rtmr0_default: rtmr0-reset-n-active-state {
pins = "gpio10";
diff --git a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
index ab309d547ed5..500809772097 100644
--- a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
+++ b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
@@ -1131,9 +1131,6 @@ &mdss_dp3_phy {
};
&pcie4 {
- perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie4_default>;
pinctrl-names = "default";
@@ -1148,6 +1145,9 @@ &pcie4_phy {
};
&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
wifi@0 {
compatible = "pci17cb,1107";
reg = <0x10000 0x0 0x0 0x0 0x0>;
@@ -1165,9 +1165,6 @@ wifi@0 {
};
&pcie6a {
- perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
-
vddpe-3v3-supply = <&vreg_nvme>;
pinctrl-0 = <&pcie6a_default>;
@@ -1183,6 +1180,11 @@ &pcie6a_phy {
status = "okay";
};
+&pcie6a_port0 {
+ reset-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>;
+};
+
&pm8550_pwm {
status = "okay";
};
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH v5 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Neil Armstrong @ 2026-03-30 7:49 UTC (permalink / raw)
To: Bryan O'Donoghue, Konrad Dybcio, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Bryan O'Donoghue, Vladimir Zapolskiy, linux-arm-msm,
linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <c5278028-dfe9-4d09-970a-a25977967bdd@linaro.org>
On 3/27/26 18:42, Bryan O'Donoghue wrote:
> On 27/03/2026 15:28, Neil Armstrong wrote:
>>> To be frankly honest you can make an argument for it either way. However my honestly held position is analysing other upstream implementations connecting to the PHY means we can't make the PHY device a drivers/phy device - it would have to be a V4L2 device and then for me the question is why is that even required ?
>>
>> This is plain wrong, DT definition is different from software implementation, you can do whatever you want if you describe HW accurately.
>
> I'm not sure what point it is you are trying to make here. Are you trying to say drivers/phy is OK with you but you want an endpoint ? If so, please just say so.
I'm against using the "phys = <>" property in the CAMSS to reference the PHYs, a "PHY" in the classic terminology is tied to a single consumer, and if it can be shared to multiple consumer you must model a mux or whatever in the middle.
The PHY API as an internal software implementation is probably fine, even if it makes implementation of split mode much much harder and doesn't really solve anything, you can just call init()/poweron()/poweroff()/exit() directly from the CSIPHY media callbacks.
>
> I can see an argument for that hence my response to Konrad, I just don't see why its a Qualcomm specific argument and of course understood stuff bubbles up in review, we have a public debate and come to a consensus - that's a good thing.
>
> However, I'd want wider buy-in and understanding that endpoints in the PHYs is a more accurate description of the data-flow.
It is, and it was designed for that, and extensively used in the media DT representation, so I wonder here you would not use it...
In an ideal world, you would add nodes for each CAMSS hw elements and adds port/endpoints links between all nodes to describe the data graph, this would be used to construct the media controller graph, and make it much easier supporting new hardware.
>
> We've been applying DT bindings aplenty without that so far. So we would establish new CSI2 PHY bindings should represent the sensor endpoints.
We've been using a dummy representation of CAMM in a single node with only endpoints connecting to the sensors and hiding all the hardware layout in code, it doesn't scale and makes supporting new HW hard.
I mean this is common sense, why would we continue to stick to the current CAMSS bindings ???
>
> Is that what you want ?
>
>> The CSIPHYs are not tied to a single "consumer" block, they can be connected to different consumers at runtime, which is not something classic PHY devices are designed for. So they are de facto a media element in the dynamic camera pipeline.
>
> The existing CAMSS binding and media graph are not changed by this series.
This is not my point, I don't care about the software implementation at all, I care about accurate hardware representation. Using the "phys = <>" property does not describe hardware accurately.
In other words: The CSIPHY are not connected to CAMSS. This is _not_ true, tying the CSIPHYs to the CAMSS block hides the real data muxing in software.
Please remind DT is used by multiple operating systems, and properly describing hardware in DT will help have good software support over all OSes, not just Linux.
>
>> And actually Rob Herring asked use to define the complete data flow, it was a strong requirement. I don't see why we wouldn't here.
>
> I'm implementing feedback from Rob.
>
> https://lore.kernel.org/linux-media/20250710230846.GA44483-robh@kernel.org/
Where did he ask using the PHY DT bindings ? Is he aware those CSIPHYs are muxed to multiple consumers which are burried in the CAMSS code ?
>
> To me, here is where we stand:
>
> - Individual nodes - we all agree that
> - As sub-nodes - I think the majority agrees this Krzsztof, Dmitry
> I'm fine with it too.
> - drivers/phy - I think we are accepting this is also fine ?
Like I said this adds a supplementary API layer for no reason and will make life harder, but I don't care personally.
> - endpoints should flow into the PHY and then back to the controller
>
> I get that argument. In fact I _like_ that argument at least I like my conception of that argument.
>
> I'll stipulate to that argument meaning then that, new CSI2 PHYs shall include endpoints for this purpose globally.
>
> As I've said before, there's nothing Qualcomm specific about this discussion, really.
There is, because the current Qualcomm CAMSS bindings are insufficient and should be entirely redesigned from the ground up to properly describe the HW.
Neil
>
> ---
> bod
--
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