* Re: [PATCH v5 4/4] phy: qualcomm: add MSM8974 HDMI PHY support
From: Dmitry Baryshkov @ 2026-03-18 17:15 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Vinod Koul, Neil Armstrong, linux-kernel, linux-arm-msm,
dri-devel, freedreno, linux-phy, Dmitry Baryshkov
In-Reply-To: <5a464fca-7be5-44a6-b124-7b80ea859a9e@oss.qualcomm.com>
On Wed, Mar 18, 2026 at 10:22:08AM +0100, Konrad Dybcio wrote:
> On 3/14/26 6:06 AM, Dmitry Baryshkov wrote:
> > From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >
> > Add support for HDMI PHY on Qualcomm MSM8974 / APQ8074 platforms.
> >
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> > ---
>
> [...]
>
> > + sdm_freq_seed = mult_frac(remain, 0x10000, int_ref_freq);
> > +
> > + val = (ref_freq_mult_2 ? BIT(0) : 0) |
> > + ((refclk_div - 1) << 2);
> > + writel(val, base + UNIPHY_PLL_REFCLK_CFG);
> > +
> > + writel(sdm_mode ? 0 : 0x40 + dc_offset, base + UNIPHY_PLL_SDM_CFG0);
> > +
> > + writel(dither ? 0x40 + dc_offset : 0, base + UNIPHY_PLL_SDM_CFG1);
> > +
> > + writel(sdm_freq_seed & 0xff, base + UNIPHY_PLL_SDM_CFG2);
>
> Some beautification (BIT(), FIELD_..(), defined magic values) would be
> really nice to see.. although I'm not sure how much you can do with the
> PLL registers..
I can try doing a bit of it, but not that much. The HDMI PHY is mostly
unspecified for that platform. The code here is mostly based on the
study of the existing values in downstream and corresponding DSI PHY
(which uses the same UNIPHY core).
>
> [...]
>
> > + ref_freq = ref_freq * 5 / 1000;
>
> mult_frac()
ack
>
> [...]
>
> > + rate = (dc_offset + 1) * parent_rate;
> > + rate += mult_frac(fraq_n, parent_rate, 0x10000);
> > +
> > + rate *= (refclk_cfg >> 2) * 0x3 + 1;
>
> Really strange calculation, but in the end this is (n * 0.75)+1 -
> mult_frac()?
It might be based on some other dividers which I didn't recognize.
Anyway, yes, mult_frac() would work.
>
> > +
> > + return rate;
> > +}
> > +
> > +static const unsigned int qcom_hdmi_8974_divs[] = {1, 2, 4, 6};
> > +
> > +static unsigned long qcom_hdmi_8974_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 = hdmi_pll_read(hdmi_phy, UNIPHY_PLL_POSTDIV1_CFG);
> > + unsigned long rate = qcom_uniphy_recalc(hdmi_phy->pll_reg, parent_rate);
> > +
> > + return rate / HDMI_8974_COMMON_DIV / qcom_hdmi_8974_divs[div_idx & 0x3];
>
> nit: double space
>
>
> > +}
> > +
> > +static int qcom_hdmi_8974_pll_determine_rate(struct clk_hw *hw,
> > + struct clk_rate_request *req)
> > +{
> > + req->rate = clamp(req->rate,
> > + HDMI_8974_VCO_MIN_FREQ / HDMI_8974_COMMON_DIV / 6,
> > + HDMI_8974_VCO_MAX_FREQ / HDMI_8974_COMMON_DIV / 1);
>
> I don't know if it's a good direction, but maybe:
>
> const unsigned long max_rate = HDMI_8974_VCO_MAX_FREQ / HDMI_8974_COMMON_DIV;
>
> clamp(req->rate, max_rate / 6, max_rate)
Note, it is clamp (min_rate / 6, max_rate)
>
> ?
>
> [...]
>
> > +static int qcom_hdmi_msm8974_phy_find_div(unsigned long long pixclk)
> > +{
> > + int i;
> > + unsigned long long min_freq = HDMI_8974_VCO_MIN_FREQ / HDMI_8974_COMMON_DIV;
>
> reverse-Christmas-tree?
>
> > +
> > + if (pixclk > HDMI_8974_VCO_MAX_FREQ / HDMI_8974_COMMON_DIV)
> > + return -E2BIG;
>
> include/uapi/asm-generic/errno-base.h
> 11:#define E2BIG 7 /* Argument list too long */
>
> -EINVAL?
Ok
>
> 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 v4 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Bryan O'Donoghue @ 2026-03-18 15:47 UTC (permalink / raw)
To: Neil Armstrong, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Vladimir Zapolskiy, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <16b10f17-ecd3-4cdd-ac3f-f64127d60ace@linaro.org>
On 18/03/2026 15:07, Neil Armstrong wrote:
> On 3/18/26 14:17, Bryan O'Donoghue wrote:
>> On 18/03/2026 10:15, Neil Armstrong wrote:
>>>> + /*
>>>> + * phy_configure_opts_mipi_dphy.lanes starts from zero to
>>>> + * the maximum number of enabled lanes.
>>>> + *
>>>> + * TODO: add support for bitmask of enabled lanes and polarities
>>>> + * of those lanes to the phy_configure_opts_mipi_dphy struct.
>>>> + * For now take the polarities as zero and the position as fixed
>>>> + * this is fine as no current upstream implementation maps otherwise.
>>>> + */
>>>
>>> This is wrong since you loose the lanes mapping defined in DT, which is still in CAMSS
>>> but is a PHY property. The lanes layout is not a property of the CSI controller,
>>> CSI controller only need to know the lanes count, and not the layout.
>>
>> Lane layout is a PHY concern but, the PHY API gives us phy_configure_opts_mipi_dphy which should be extended to provide layout and polarity. This would then be of benefit to more than just qcom/camss.
>
> Why ? the only concern between a controller and a PHY is the lane count to calculate the bandwidth, the actual pin layout is certainly not a controller concern.
Controllers already get the lane count by way of data-lanes = <x y z q>
or <x y> or <x> if we didn't do that we would need to specify the
data-lanes in the controller and again in the PHY.
>>
>> Right now none of the CAMSS users for this driver depend on any other mapping and I propose a separate series to fix phy_configure_opts_mipi_dphy rather than introduce data-lanes to DPHY.
>
> None of the upstream users of camss.
No, we are establishing from x1 use of standard drivers/phy. New users
will do it this way. The posted dtsi for the laptops can use the linear
lane layout and default polarities.
In a follow on series we can extend phy_configure_opts_mipi_dphy to
parse data-lanes = <> into count and mask, to the benefit of any user of
phy_configure_opts_mipi_dphy.
Since that will touch more then qcom specific stuff and will touch at
least two subsystems, that should be its own separate series.
> The problem is even larger, as you replied in [1], the csiphy is still exposed as a media element from the CAMSS driver, this means this driver is not complete,
> it should be a media driver entirely with eventually an internal PHY aux driver, but this would be entirely implementation specific.
>
> Either the PHY is standalone and the PHY consumer only calls phy_open/init/configure/power_on/power_off/exit, otherwise it's not a fully standaline PHY but a composite device like here.
This is not a composite device any more than the existing upstream
implementations which follow the same model:
- Cadence CSI2RX + Cadence DPHY (TI J721E/AM62A)
- Rockchip rkisp1 + phy-rockchip-inno-csidphy
Both use phys = <&phandle>, the media driver manages V4L2 endpoints
and lane counts, the PHY driver handles the electrical layer via
phy_configure().
To this list we will add qcom camss, there's nothing exotic being proposed.
> I propose that you write a proper media driver for the qcom csiphy, which eventually spins a PHY driver as an aux device.
None of these SoC D-PHYs are written as V4L2 media drivers that spawn
auxiliary devices. They all use the phys = <&phandle> model. The media
driver manages the V4L2 endpoints and lane counts, passing the
configuration down via phy_configure_opts_mipi_dphy.
I just don't see what is so special about CAMSS that it needs to have
its own special PHY implementation. drivers/phy the standard API and
specification of data-lanes etc in the controller seems pretty "bog
standard".
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v4 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Dmitry Baryshkov @ 2026-03-18 15:27 UTC (permalink / raw)
To: Neil Armstrong
Cc: Bryan O'Donoghue, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bryan O'Donoghue, Vladimir Zapolskiy, linux-arm-msm,
linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <16b10f17-ecd3-4cdd-ac3f-f64127d60ace@linaro.org>
On Wed, Mar 18, 2026 at 04:07:39PM +0100, Neil Armstrong wrote:
> On 3/18/26 14:17, Bryan O'Donoghue wrote:
> > On 18/03/2026 10:15, Neil Armstrong wrote:
> > > > + /*
> > > > + * phy_configure_opts_mipi_dphy.lanes starts from zero to
> > > > + * the maximum number of enabled lanes.
> > > > + *
> > > > + * TODO: add support for bitmask of enabled lanes and polarities
> > > > + * of those lanes to the phy_configure_opts_mipi_dphy struct.
> > > > + * For now take the polarities as zero and the position as fixed
> > > > + * this is fine as no current upstream implementation maps otherwise.
> > > > + */
> > >
> > > This is wrong since you loose the lanes mapping defined in DT, which is still in CAMSS
> > > but is a PHY property. The lanes layout is not a property of the CSI controller,
> > > CSI controller only need to know the lanes count, and not the layout.
> >
> > Lane layout is a PHY concern but, the PHY API gives us phy_configure_opts_mipi_dphy which should be extended to provide layout and polarity. This would then be of benefit to more than just qcom/camss.
>
> Why ? the only concern between a controller and a PHY is the lane count to calculate the bandwidth, the actual pin layout is certainly not a controller concern.
I think that the DT should be providing the information about the
connection of the lanes and their number on the board. Then the CSI host
might want to limit this further for whatever reasons. But I don't think
that the properties of the lanes should be configurable between the
controller and the PHY.
>
> >
> > Right now none of the CAMSS users for this driver depend on any other mapping and I propose a separate series to fix phy_configure_opts_mipi_dphy rather than introduce data-lanes to DPHY.
>
> None of the upstream users of camss.
>
> The problem is even larger, as you replied in [1], the csiphy is still exposed as a media element from the CAMSS driver, this means this driver is not complete,
> it should be a media driver entirely with eventually an internal PHY aux driver, but this would be entirely implementation specific.
>
> Either the PHY is standalone and the PHY consumer only calls phy_open/init/configure/power_on/power_off/exit, otherwise it's not a fully standaline PHY but a composite device like here.
>
> I propose that you write a proper media driver for the qcom csiphy, which eventually spins a PHY driver as an aux device.
Why do you want a media driver? Isn't PHY driver enough?
--
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 v5 1/4] drm/msm/hdmi: switch to generic PHY subsystem
From: Dmitry Baryshkov @ 2026-03-14 5:06 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: <20260314-fd-hdmi-phy-v5-0-58122ae96d3b@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 | 444 +++++++++++++
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 | 81 +++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c | 185 ++++++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c | 443 +++++++++++++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c | 496 +++++++++++++++
drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h | 77 +++
23 files changed, 2276 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..db7fa2df1a36
--- /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)
+{
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_ANA_CFG0, 0x1b);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_ANA_CFG1, 0xf2);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_BIST_CFG0, 0x0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_BIST_PATN0, 0x0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_BIST_PATN1, 0x0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_BIST_PATN2, 0x0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_BIST_PATN3, 0x0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_PD_CTRL1, 0x20);
+
+ return 0;
+}
+
+static int qcom_hdmi_msm8974_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x74_PD_CTRL0, 0x7f);
+
+ 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..d2cf3e8dfc7d
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c
@@ -0,0 +1,444 @@
+// 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 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 = hdmi_pll_read(hdmi_phy, REG_HDMI_8960_PHY_PLL_REFCLK_CFG);
+ if (refclk_cfg & BIT(1))
+ parent_rate /= 2;
+ if (refclk_cfg & BIT(3))
+ parent_rate *= 2;
+
+ val = hdmi_pll_read(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG0);
+ if (val & 0x40) {
+ dc_offset = val & 0x3f;
+ fraq_n = 0;
+ } else {
+ dc_offset = hdmi_pll_read(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG1) & 0x3f;
+ fraq_n = hdmi_pll_read(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG2) |
+ (hdmi_pll_read(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG3) << 8);
+ }
+
+ rate = (dc_offset + 1) * parent_rate;
+ rate += mult_frac(fraq_n, parent_rate, 0x10000);
+
+ return rate;
+}
+
+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;
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_REFCLK_CFG, val);
+
+ 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);
+
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0, lf_cfg0);
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1, lf_cfg1);
+
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG0,
+ (sdm_mode ? 0 : 0x40) | dc_offset);
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG1,
+ 0x40 | dc_offset);
+
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG2,
+ sdm_freq_seed & 0xff);
+
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG3,
+ (sdm_freq_seed >> 8) & 0xff);
+
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_SDM_CFG4,
+ sdm_freq_seed >> 16);
+
+ vco_freq /= 1000;
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0, vco_freq & 0xff);
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1, vco_freq >> 8);
+
+ hdmi_pll_write(hdmi_phy, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2, 0x3b);
+
+ 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 = hdmi_pll_read(hdmi_phy, 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)
+{
+ req->rate = clamp(req->rate,
+ HDMI_8960_VCO_MIN_FREQ / HDMI_8960_COMMON_DIV / 6,
+ HDMI_8960_VCO_MAX_FREQ / HDMI_8960_COMMON_DIV / 1);
+
+ 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 *phy)
+{
+ int pll_lock_retry = 10;
+ unsigned int val;
+ int ret;
+
+ /* Assert PLL S/W reset */
+ hdmi_pll_write(phy, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
+ hdmi_pll_write(phy, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
+ hdmi_pll_write(phy, 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 */
+ hdmi_pll_write(phy, 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 = hdmi_pll_read(phy, 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;
+ hdmi_pll_write(phy, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
+ hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80);
+
+ while (--pll_lock_retry > 0) {
+ ret = readl_poll_timeout(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
+ */
+ hdmi_pll_write(phy, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
+ udelay(10);
+ hdmi_pll_write(phy, 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);
+ }
+
+ return ret;
+}
+
+static int qcom_hdmi_msm8960_phy_find_div(unsigned long long pixclk)
+{
+ int i;
+ unsigned long long min_freq = HDMI_8960_VCO_MIN_FREQ / HDMI_8960_COMMON_DIV;
+
+ 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 *phy)
+{
+ unsigned int val;
+
+ 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 = hdmi_pll_read(phy, REG_HDMI_8960_PHY_PLL_PWRDN_B);
+ val |= HDMI_8960_PHY_REG12_SW_RESET;
+ val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
+ hdmi_pll_write(phy, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
+ /* 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;
+
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG2, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG0, 0x1b);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG1, 0xf2);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG4, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG5, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG6, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG7, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG8, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG9, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG10, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG11, 0x00);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG3, 0x20);
+
+ return 0;
+}
+
+static int qcom_hdmi_msm8960_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8960_PHY_REG2, 0x7f);
+
+ 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..ae834f0827fa
--- /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: */
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG0,
+ FIELD_PREP(HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK, 3));
+
+ if (pixclock == 27 * HZ_PER_MHZ) {
+ /* video_format == HDMI_VFRMT_720x480p60_16_9 */
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG1,
+ FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) |
+ FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 3));
+ } else {
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG1,
+ FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) |
+ FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 4));
+ }
+
+ /* No matter what, start from the power down mode: */
+ hdmi_phy_write(hdmi_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(hdmi_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(hdmi_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(hdmi_phy, REG_HDMI_8x60_PHY_REG3,
+ HDMI_8x60_PHY_REG3_PLL_ENABLE);
+
+ /* ASIC power on; PHY REG9 = 0 */
+ hdmi_phy_write(hdmi_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(hdmi_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(hdmi_phy, REG_HDMI_8x60_PHY_REG2,
+ HDMI_8x60_PHY_REG2_PD_DESER);
+
+ /* If the RX detector is needed: */
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2,
+ HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
+ HDMI_8x60_PHY_REG2_PD_DESER);
+
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG4, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG5, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG6, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG7, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG8, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG9, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG10, 0);
+ hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG11, 0);
+
+ /* If we want to use lock enable based on counting: */
+ hdmi_phy_write(hdmi_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);
+
+ return 0;
+}
+
+static int qcom_hdmi_msm8x60_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy)
+{
+ /* Turn off Driver */
+ hdmi_phy_write(hdmi_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(hdmi_phy, REG_HDMI_8x60_PHY_REG3, 0);
+ /* Power down PHY, but keep RX-sense: */
+ hdmi_phy_write(hdmi_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);
+
+ 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..5562a3ac4840
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h
@@ -0,0 +1,81 @@
+/* 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;
+};
+
+static inline void hdmi_phy_write(struct qcom_hdmi_preqmp_phy *phy, int offset,
+ u32 data)
+{
+ writel(data, phy->phy_reg + offset);
+}
+
+static inline u32 hdmi_phy_read(struct qcom_hdmi_preqmp_phy *phy, int offset)
+{
+ return readl(phy->phy_reg + offset);
+}
+
+static inline void hdmi_pll_write(struct qcom_hdmi_preqmp_phy *phy, int offset,
+ u32 data)
+{
+ writel(data, phy->pll_reg + offset);
+}
+
+static inline u32 hdmi_pll_read(struct qcom_hdmi_preqmp_phy *phy, int offset)
+{
+ return readl(phy->pll_reg + offset);
+}
+
+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..e35ed12daf30
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c
@@ -0,0 +1,443 @@
+// 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 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");
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_PD_CTL, 0x0);
+ udelay(500);
+
+ /* Power up sequence */
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_BG_CTRL, 0x04);
+
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_PD_CTL, 0x1);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_RESETSM_CNTRL, 0x20);
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_TX0_TX1_LANE_CTL, 0x0f);
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_TX2_TX3_LANE_CTL, 0x0f);
+
+ hdmi_tx_chan_write(hdmi_phy, 0, QSERDES_TX_LANE_MODE, 0x43);
+ hdmi_tx_chan_write(hdmi_phy, 2, QSERDES_TX_LANE_MODE, 0x43);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1e);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SYSCLK_EN_SEL, 0x37);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SYS_CLK_CTRL, 0x02);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CLK_ENABLE1, 0x0e);
+
+ if (frac_start != 0 || gen_ssc) {
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_PLL_CCTRL_MODE0, 0x28);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CP_CTRL_MODE0,
+ 11000000 / (parent_rate / 20));
+ integloop_gain = (64 * parent_rate) / HDMI_DEFAULT_REF_CLOCK;
+ } else {
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_PLL_CCTRL_MODE0, 0x01);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_PLL_RCTRL_MODE0, 0x10);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CP_CTRL_MODE0, 0x23);
+ integloop_gain = (1022 * parent_rate) / (100 * 1000 * 1000);
+ }
+
+ /* Bypass VCO calibration */
+ if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SVS_MODE_CLK_SEL, 1);
+ integloop_gain <<= 1;
+ } else {
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SVS_MODE_CLK_SEL, 2);
+ integloop_gain <<= 2;
+ }
+
+ integloop_gain = min_t(u32, integloop_gain, 2046);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_BG_TRIM, 0x0f);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_PLL_IVCO, 0x0f);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_VCO_TUNE_CTRL, 0);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_BG_CTRL, 0x06);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CLK_SELECT, 0x30);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_HSCLK_SEL, 0x20 | pd.hsclk_divsel);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_LOCK_CMP_EN, 0x0);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_DEC_START_MODE0, dec_start);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_DIV_FRAC_START1_MODE0,
+ frac_start & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_DIV_FRAC_START2_MODE0,
+ (frac_start >> 8) & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_DIV_FRAC_START3_MODE0,
+ (frac_start >> 16) & 0xf);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_INTEGLOOP_GAIN0_MODE0,
+ integloop_gain & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_INTEGLOOP_GAIN1_MODE0,
+ (integloop_gain >> 8) & 0xff);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_LOCK_CMP1_MODE0,
+ pll_cmp & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_LOCK_CMP2_MODE0,
+ (pll_cmp >> 8) & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_LOCK_CMP3_MODE0,
+ (pll_cmp >> 16) & 0x3);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_VCO_TUNE_MAP, 0x00);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CORE_CLK_EN, 0x2c);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CORECLK_DIV, 5);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_CMN_CONFIG, 0x02);
+
+ hdmi_pll_write(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(hdmi_phy, i, QSERDES_TX_CLKBUF_ENABLE, 0x03);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_BAND, pd.tx_band_sel + 4);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_RESET_TSYNC_EN, 0x03);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_VMODE_CTRL1, 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_DRV_LVL_OFFSET, 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_RES_CODE_LANE_OFFSET, 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x03);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_HP_PD_ENABLES,
+ i != 3 ? 0xc : 0x3);
+ }
+
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_DRV_LVL,
+ i != 3 ? 0x25 : 0x22);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_EMP_POST1_LVL,
+ i != 3 ? 0x23 : 0x27);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_VMODE_CTRL2,
+ i != 3 ? 0x0d : 0x00);
+ }
+ } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_DRV_LVL, 0x25);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_EMP_POST1_LVL, 0x23);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_VMODE_CTRL2,
+ i != 3 ? 0x0d : 0x00);
+ }
+ } else {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_DRV_LVL, 0x20);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_TX_EMP_POST1_LVL, 0x20);
+ hdmi_tx_chan_write(hdmi_phy, i, QSERDES_TX_VMODE_CTRL2, 0x0e);
+ }
+ }
+
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_MODE, 0x10);
+ else
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_MODE, 0x00);
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_PD_CTL, 0x1f);
+
+ 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;
+ }
+
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_CFG, 0x1);
+ udelay(100);
+
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_CFG, 0x19);
+ 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++)
+ hdmi_tx_chan_write(hdmi_phy, i,
+ QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+ 0x6f);
+
+ /* Disable SSC */
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SSC_PER1, 0x0);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SSC_PER2, 0x0);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SSC_STEP_SIZE1, 0x0);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SSC_STEP_SIZE2, 0x0);
+ hdmi_pll_write(hdmi_phy, QSERDES_COM_SSC_EN_CENTER, 0x2);
+
+ 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 */
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_CFG, 0x18);
+ udelay(1);
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_CFG, 0x19);
+
+ return 0;
+}
+
+static int qmp_hdmi_8996_phy_power_off(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ hdmi_phy_write(hdmi_phy, HDMI_8996_PHY_CFG, 0x6);
+ 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 cmp1, cmp2, cmp3, pll_cmp;
+
+ cmp1 = hdmi_pll_read(phy, QSERDES_COM_LOCK_CMP1_MODE0);
+ cmp2 = hdmi_pll_read(phy, QSERDES_COM_LOCK_CMP2_MODE0);
+ cmp3 = hdmi_pll_read(phy, QSERDES_COM_LOCK_CMP3_MODE0);
+
+ pll_cmp = cmp1 | (cmp2 << 8) | (cmp3 << 16);
+
+ 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 = hdmi_pll_read(phy, 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..762608a664e5
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c
@@ -0,0 +1,496 @@
+// 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 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");
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_PD_CTL, 0x0);
+ udelay(500);
+
+ /* Power up sequence */
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_PD_CTL, 0x1);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_RESETSM_CNTRL, 0x20);
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_CMN_CTRL, 0x6);
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i,
+ HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND,
+ pd.tx_band_sel);
+ hdmi_tx_chan_write(hdmi_phy, i,
+ HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE,
+ 0x1);
+ hdmi_tx_chan_write(hdmi_phy, i,
+ HDMI_8998_PHY_TXn_LANE_MODE,
+ 0x20);
+ }
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x02);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x0B);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_SYSCLK_EN_SEL, 0x37);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_SYS_CLK_CTRL, 0x02);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_CLK_ENABLE1, 0x0E);
+
+ if (frac_start != 0 || gen_ssc) {
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x34);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_CP_CTRL_MODE0, 0x08);
+ integloop_gain = 0x3f;
+ } else {
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x02);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x18);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_CP_CTRL_MODE0, 0x30);
+ integloop_gain = 0xc4;
+ }
+
+ /* Bypass VCO calibration */
+ if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_SVS_MODE_CLK_SEL, 1);
+ integloop_gain <<= 1;
+ } else {
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_SVS_MODE_CLK_SEL, 2);
+ integloop_gain <<= 2;
+ }
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_PLL_IVCO, 0x07);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_CLK_SELECT, 0x30);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_HSCLK_SEL, 0x20 | pd.hsclk_divsel);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_LOCK_CMP_EN, 0x0);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_DEC_START_MODE0, dec_start);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_DIV_FRAC_START1_MODE0,
+ frac_start & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_DIV_FRAC_START2_MODE0,
+ (frac_start >> 8) & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_DIV_FRAC_START3_MODE0,
+ (frac_start >> 16) & 0xf);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0,
+ integloop_gain & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0,
+ (integloop_gain >> 8) & 0xff);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_LOCK_CMP1_MODE0,
+ pll_cmp & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_LOCK_CMP2_MODE0,
+ (pll_cmp >> 8) & 0xff);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_LOCK_CMP3_MODE0,
+ (pll_cmp >> 16) & 0x3);
+
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_VCO_TUNE_MAP, 0x00);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_CORE_CLK_EN, 0x2c);
+ hdmi_pll_write(hdmi_phy, QSERDES_V3_COM_CORECLK_DIV_MODE0, 5);
+
+ /* 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++) {
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL,
+ 0xf);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_EMP_POST1_LVL,
+ i == 3 ? 0x00 :
+ i == 1 ? 0x02 : 0x03);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_1,
+ 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_2,
+ i == 3 ? 0x00 : 0x1c);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET,
+ (i == 0 || i == 3) ? 0x03 : 0x00);
+ }
+ } else if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL,
+ 0x0f);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_EMP_POST1_LVL,
+ i == 3 ? 0x00 : 0x03);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_1,
+ 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_2,
+ i == 3 ? 0x18 : 0x16);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET,
+ i == 0 ? 0x03 : 0x00);
+ }
+ } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL,
+ 0x0f);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_EMP_POST1_LVL,
+ i == 3 ? 0x00 : 0x05);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_1,
+ 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_2,
+ 0x0e);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET,
+ 0x00);
+ }
+ } else {
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL,
+ i == 3 ? 0x00 : 0x01);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_EMP_POST1_LVL,
+ 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_1,
+ 0x00);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_PRE_DRIVER_2,
+ i == 3 ? 0x18 : 0x16);
+ hdmi_tx_chan_write(hdmi_phy, i, HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET,
+ 0x00);
+ }
+ }
+
+ if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_MODE, 0x5);
+ else
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_MODE, 0x4);
+
+ for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {
+ hdmi_tx_chan_write(hdmi_phy, i,
+ HDMI_8998_PHY_TXn_LANE_CONFIG,
+ 0x10);
+ }
+
+ 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;
+ }
+
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_CFG, 0x1);
+ udelay(100);
+
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_CFG, 0x59);
+ 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++) {
+ hdmi_tx_chan_write(hdmi_phy, i,
+ HDMI_8998_PHY_TXn_LANE_CONFIG, 0x1f);
+ }
+
+ 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 */
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_CFG, 0x58);
+ udelay(1);
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_CFG, 0x59);
+
+ return 0;
+}
+
+static int qmp_hdmi_8998_phy_power_off(struct phy *phy)
+{
+ struct qmp_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ hdmi_phy_write(hdmi_phy, HDMI_8998_PHY_PD_CTL, 0);
+ 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 cmp1, cmp2, cmp3, pll_cmp;
+
+ cmp1 = hdmi_pll_read(phy, QSERDES_V3_COM_LOCK_CMP1_MODE0);
+ cmp2 = hdmi_pll_read(phy, QSERDES_V3_COM_LOCK_CMP2_MODE0);
+ cmp3 = hdmi_pll_read(phy, QSERDES_V3_COM_LOCK_CMP3_MODE0);
+
+ pll_cmp = cmp1 | (cmp2 << 8) | (cmp3 << 16);
+
+ 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 = hdmi_pll_read(phy, 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..cac28bff3964
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h
@@ -0,0 +1,77 @@
+/* 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)
+
+static inline void hdmi_phy_write(struct qmp_hdmi_phy *phy, int offset,
+ u32 data)
+{
+ writel(data, phy->phy_reg + offset);
+}
+
+static inline u32 hdmi_phy_read(struct qmp_hdmi_phy *phy, int offset)
+{
+ return readl(phy->phy_reg + offset);
+}
+
+static inline void hdmi_pll_write(struct qmp_hdmi_phy *phy, int offset,
+ u32 data)
+{
+ writel(data, phy->serdes + offset);
+}
+
+static inline u32 hdmi_pll_read(struct qmp_hdmi_phy *phy, int offset)
+{
+ return readl(phy->serdes + offset);
+}
+
+static inline void hdmi_tx_chan_write(struct qmp_hdmi_phy *phy, int channel,
+ int offset, int data)
+{
+ writel(data, phy->tx[channel] + offset);
+}
+
+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
* Re: [PATCH 00/61] treewide: Use IS_ERR_OR_NULL over manual NULL check - refactor
From: Russell King (Oracle) @ 2026-03-11 0:09 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Julia Lawall, Nicolas Palix, Chris Mason,
David Sterba, Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko,
Theodore Ts'o, Andreas Dilger, Steve French, Paulo Alcantara,
Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
Christian Schoenebeck, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Miklos Szeredi,
Konstantin Komarov, Andreas Gruenbacher, Kees Cook, Tony Luck,
Guilherme G. Piccoli, Jan Kara, Phillip Lougher, Alexander Viro,
Christian Brauner, Jan Kara, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Tejun Heo, David Vernet, Andrea Righi,
Changwoo Min, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Ben Segall, Mel Gorman,
Valentin Schneider, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Sylwester Nawrocki, Liam Girdwood,
Mark Brown, Jaroslav Kysela, Takashi Iwai, Max Filippov,
Paolo Bonzini, John Johansen, Paul Moore, James Morris,
Serge E. Hallyn, Andrew Morton, Alasdair Kergon, Mike Snitzer,
Mikulas Patocka, Benjamin Marzinski, David S. Miller, David Ahern,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Marcel Holtmann, Johan Hedberg, Luiz Augusto von Dentz,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, Jamal Hadi Salim, Jiri Pirko,
Marcelo Ricardo Leitner, Xin Long, Trond Myklebust,
Anna Schumaker, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Jon Maloy, Johannes Berg,
Catalin Marinas, John Crispin, Thomas Bogendoerfer,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Zhenyu Wang,
Zhi Wang, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Alex Deucher, Christian König, Sandy Huang,
Heiko Stübner, Andy Yan, Igor Russkikh, Andrew Lunn,
Pavan Chebbi, Michael Chan, Potnuri Bharat Teja, Tony Nguyen,
Przemek Kitszel, Taras Chornyi, Maxime Coquelin, Alexandre Torgue,
Iyappan Subramanian, Keyur Chudgar, Quan Nguyen, Heiner Kallweit,
Marc Zyngier, Thomas Gleixner, Andrew Lunn, Gregory Clement,
Sebastian Hesselbarth, Vinod Koul, Linus Walleij, Ulf Hansson,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Martin K. Petersen,
Eduardo Valentin, Keerthy, Rafael J. Wysocki, Daniel Lezcano,
Zhang Rui, Lukasz Luba, Alex Williamson, Mark Greer,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Shuah Khan, Kieran Bingham, Mauro Carvalho Chehab, Joerg Roedel,
Will Deacon, Robin Murphy, Lee Jones, Pavel Machek, Dave Penkler,
K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
Justin Sanders, Jens Axboe, Georgi Djakov, Michael Turquette,
Stephen Boyd, Philipp Zabel, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Pali Rohár, Dmitry Torokhov
In-Reply-To: <20260310-b4-is_err_or_null-v1-0-bd63b656022d@avm.de>
On Tue, Mar 10, 2026 at 12:48:26PM +0100, Philipp Hahn wrote:
> While doing some static code analysis I stumbled over a common pattern,
> where IS_ERR() is combined with a NULL check. For that there is
> IS_ERR_OR_NULL().
One thing you need to check for each of these cases is whether the tests
are actually correct.
There are certainly cases amongst those that you have identified where
the check for NULL is redundant.
For example, get_phy_device() never returns NULL, yet in your netdev
patch, you have at least one instance where the return value of
get_phy_device() is checked for NULL and IS_ERR() which you then
turn into IS_ERR_OR_NULL(). Instead, the NULL check should be dropped
(as a separate patch.)
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 00/61] treewide: Use IS_ERR_OR_NULL over manual NULL check - refactor
From: Theodore Tso @ 2026-03-10 14:23 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Julia Lawall, Nicolas Palix, Chris Mason,
David Sterba, Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko,
Andreas Dilger, Steve French, Paulo Alcantara, Ronnie Sahlberg,
Shyam Prasad N, Tom Talpey, Bharath SM, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
Chunhai Guo, Miklos Szeredi, Konstantin Komarov,
Andreas Gruenbacher, Kees Cook, Tony Luck, Guilherme G. Piccoli,
Jan Kara, Phillip Lougher, Alexander Viro, Christian Brauner,
Jan Kara, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Tejun Heo, David Vernet, Andrea Righi, Changwoo Min, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Ben Segall, Mel Gorman, Valentin Schneider, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Sylwester Nawrocki, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai, Max Filippov, Paolo Bonzini, John Johansen,
Paul Moore, James Morris, Serge E. Hallyn, Andrew Morton,
Alasdair Kergon, Mike Snitzer, Mikulas Patocka,
Benjamin Marzinski, David S. Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Marcel Holtmann,
Johan Hedberg, Luiz Augusto von Dentz, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, Jamal Hadi Salim, Jiri Pirko,
Marcelo Ricardo Leitner, Xin Long, Trond Myklebust,
Anna Schumaker, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Jon Maloy, Johannes Berg,
Catalin Marinas, Russell King, John Crispin, Thomas Bogendoerfer,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Zhenyu Wang,
Zhi Wang, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Alex Deucher, Christian König, Sandy Huang,
Heiko Stübner, Andy Yan, Igor Russkikh, Andrew Lunn,
Pavan Chebbi, Michael Chan, Potnuri Bharat Teja, Tony Nguyen,
Przemek Kitszel, Taras Chornyi, Maxime Coquelin, Alexandre Torgue,
Iyappan Subramanian, Keyur Chudgar, Quan Nguyen, Heiner Kallweit,
Marc Zyngier, Thomas Gleixner, Andrew Lunn, Gregory Clement,
Sebastian Hesselbarth, Vinod Koul, Linus Walleij, Ulf Hansson,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Martin K. Petersen,
Eduardo Valentin, Keerthy, Rafael J. Wysocki, Daniel Lezcano,
Zhang Rui, Lukasz Luba, Alex Williamson, Mark Greer,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Shuah Khan, Kieran Bingham, Mauro Carvalho Chehab, Joerg Roedel,
Will Deacon, Robin Murphy, Lee Jones, Pavel Machek, Dave Penkler,
K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
Justin Sanders, Jens Axboe, Georgi Djakov, Michael Turquette,
Stephen Boyd, Philipp Zabel, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Pali Rohár, Dmitry Torokhov
In-Reply-To: <20260310-b4-is_err_or_null-v1-0-bd63b656022d@avm.de>
On Tue, Mar 10, 2026 at 12:48:26PM +0100, Philipp Hahn wrote:
> While doing some static code analysis I stumbled over a common pattern,
> where IS_ERR() is combined with a NULL check. For that there is
> IS_ERR_OR_NULL().
>
> I've written a Coccinelle patch to find and patch those instances.
> The patches follow grouped by subsystem.
I'm going to gently suggest that you *not* try to do this as a
tree-wide change, since we don't need to change some interface
requiring a global, flag day change. This is instead a cleanup, which
maybe makes the code slightly better, but which also has a the
downside of breaking lots of inflight development patches by
potentially causing merge or patch conflicts.
So why don't you send it to each subsystem as a separate patch or
small patch series, instead of spamming a dozen-plus mailing lists,
are probably hundreds of developers, most of whom aren't going to
care about changs in some far flung part of the kernel?
Regards,
- Ted
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 00/61] treewide: Use IS_ERR_OR_NULL over manual NULL check - refactor
From: Steven Rostedt @ 2026-03-10 14:14 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Julia Lawall, Nicolas Palix, Chris Mason,
David Sterba, Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko,
Theodore Ts'o, Andreas Dilger, Steve French, Paulo Alcantara,
Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
Christian Schoenebeck, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Miklos Szeredi,
Konstantin Komarov, Andreas Gruenbacher, Kees Cook, Tony Luck,
Guilherme G. Piccoli, Jan Kara, Phillip Lougher, Alexander Viro,
Christian Brauner, Jan Kara, Masami Hiramatsu, Mathieu Desnoyers,
Tejun Heo, David Vernet, Andrea Righi, Changwoo Min, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Ben Segall, Mel Gorman, Valentin Schneider, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Sylwester Nawrocki, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai, Max Filippov, Paolo Bonzini, John Johansen,
Paul Moore, James Morris, Serge E. Hallyn, Andrew Morton,
Alasdair Kergon, Mike Snitzer, Mikulas Patocka,
Benjamin Marzinski, David S. Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Marcel Holtmann,
Johan Hedberg, Luiz Augusto von Dentz, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, Jamal Hadi Salim, Jiri Pirko,
Marcelo Ricardo Leitner, Xin Long, Trond Myklebust,
Anna Schumaker, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Jon Maloy, Johannes Berg,
Catalin Marinas, Russell King, John Crispin, Thomas Bogendoerfer,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Zhenyu Wang,
Zhi Wang, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Alex Deucher, Christian König, Sandy Huang,
Heiko Stübner, Andy Yan, Igor Russkikh, Andrew Lunn,
Pavan Chebbi, Michael Chan, Potnuri Bharat Teja, Tony Nguyen,
Przemek Kitszel, Taras Chornyi, Maxime Coquelin, Alexandre Torgue,
Iyappan Subramanian, Keyur Chudgar, Quan Nguyen, Heiner Kallweit,
Marc Zyngier, Thomas Gleixner, Andrew Lunn, Gregory Clement,
Sebastian Hesselbarth, Vinod Koul, Linus Walleij, Ulf Hansson,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Martin K. Petersen,
Eduardo Valentin, Keerthy, Rafael J. Wysocki, Daniel Lezcano,
Zhang Rui, Lukasz Luba, Alex Williamson, Mark Greer,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Shuah Khan, Kieran Bingham, Mauro Carvalho Chehab, Joerg Roedel,
Will Deacon, Robin Murphy, Lee Jones, Pavel Machek, Dave Penkler,
K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
Justin Sanders, Jens Axboe, Georgi Djakov, Michael Turquette,
Stephen Boyd, Philipp Zabel, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Pali Rohár, Dmitry Torokhov
In-Reply-To: <20260310-b4-is_err_or_null-v1-0-bd63b656022d@avm.de>
On Tue, 10 Mar 2026 12:48:26 +0100
Philipp Hahn <phahn-oss@avm.de> wrote:
> While doing some static code analysis I stumbled over a common pattern,
> where IS_ERR() is combined with a NULL check. For that there is
> IS_ERR_OR_NULL().
>
> I've written a Coccinelle patch to find and patch those instances.
> The patches follow grouped by subsystem.
Honestly, the IS_ERR_OR_NULL() looks worse in a lot of the locations you
updated. Just because we have IS_ERR_OR_NULL() doesn't mean we need to go
and replace every location that can use it.
NAK for any code this touches that I'm responsible for.
-- Steve
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 00/61] treewide: Use IS_ERR_OR_NULL over manual NULL check - refactor
From: Philipp Hahn @ 2026-03-10 11:48 UTC (permalink / raw)
To: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Philipp Hahn
Cc: Julia Lawall, Nicolas Palix, Chris Mason, David Sterba,
Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko, Theodore Ts'o,
Andreas Dilger, Steve French, Paulo Alcantara, Ronnie Sahlberg,
Shyam Prasad N, Tom Talpey, Bharath SM, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
Chunhai Guo, Miklos Szeredi, Konstantin Komarov,
Andreas Gruenbacher, Kees Cook, Tony Luck, Guilherme G. Piccoli,
Jan Kara, Phillip Lougher, Alexander Viro, Christian Brauner,
Jan Kara, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Tejun Heo, David Vernet, Andrea Righi, Changwoo Min, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Ben Segall, Mel Gorman, Valentin Schneider, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Sylwester Nawrocki, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai, Max Filippov, Paolo Bonzini, John Johansen,
Paul Moore, James Morris, Serge E. Hallyn, Andrew Morton,
Alasdair Kergon, Mike Snitzer, Mikulas Patocka,
Benjamin Marzinski, David S. Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Marcel Holtmann,
Johan Hedberg, Luiz Augusto von Dentz, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, Jamal Hadi Salim, Jiri Pirko,
Marcelo Ricardo Leitner, Xin Long, Trond Myklebust,
Anna Schumaker, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Jon Maloy, Johannes Berg,
Catalin Marinas, Russell King, John Crispin, Thomas Bogendoerfer,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Zhenyu Wang,
Zhi Wang, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Alex Deucher, Christian König, Sandy Huang,
Heiko Stübner, Andy Yan, Igor Russkikh, Andrew Lunn,
Pavan Chebbi, Michael Chan, Potnuri Bharat Teja, Tony Nguyen,
Przemek Kitszel, Taras Chornyi, Maxime Coquelin, Alexandre Torgue,
Iyappan Subramanian, Keyur Chudgar, Quan Nguyen, Heiner Kallweit,
Marc Zyngier, Thomas Gleixner, Andrew Lunn, Gregory Clement,
Sebastian Hesselbarth, Vinod Koul, Linus Walleij, Ulf Hansson,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Martin K. Petersen,
Eduardo Valentin, Keerthy, Rafael J. Wysocki, Daniel Lezcano,
Zhang Rui, Lukasz Luba, Alex Williamson, Mark Greer,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Shuah Khan, Kieran Bingham, Mauro Carvalho Chehab, Joerg Roedel,
Will Deacon, Robin Murphy, Lee Jones, Pavel Machek, Dave Penkler,
K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
Justin Sanders, Jens Axboe, Georgi Djakov, Michael Turquette,
Stephen Boyd, Philipp Zabel, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Pali Rohár, Dmitry Torokhov
While doing some static code analysis I stumbled over a common pattern,
where IS_ERR() is combined with a NULL check. For that there is
IS_ERR_OR_NULL().
I've written a Coccinelle patch to find and patch those instances.
The patches follow grouped by subsystem.
Patches 55-58 may be dropped as they have a (minor?) semantic change:
They use WARN_ON() or WARN_ON_ONCE(), but only in the IS_ERR() path, not
for the NULL check. Iff it is okay to print the warning also for NULL,
then the patches can be applied.
While generating the patch set `checkpatch` complained about mixing
[un]likely() with IS_ERR_OR_NULL(), which already uses likely()
internally. I found and fixed several locations, where that combination
has been used.
Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
---
Philipp Hahn (61):
Coccinelle: Prefer IS_ERR_OR_NULL over manual NULL check
btrfs: Prefer IS_ERR_OR_NULL over manual NULL check
ceph: Prefer IS_ERR_OR_NULL over manual NULL check
ext4: Prefer IS_ERR_OR_NULL over manual NULL check
smb: Prefer IS_ERR_OR_NULL over manual NULl check
9p: Prefer IS_ERR_OR_NULL over manual NULL check
erofs: Prefer IS_ERR_OR_NULL over manual NULL check
fuse: Prefer IS_ERR_OR_NULL over manual NULL check
ntfs3: Prefer IS_ERR_OR_NULL over manual NULL check
gfs2: Prefer IS_ERR_OR_NULL over manual NULL check
pstore: Prefer IS_ERR_OR_NULL over manual NULL check
quota: Prefer IS_ERR_OR_NULL over manual NULL check
squashfs: Prefer IS_ERR_OR_NULL over manual NULL check
seq_file: Prefer IS_ERR_OR_NULL over manual NULL check
trace: Prefer IS_ERR_OR_NULL over manual NULL check
sched: Prefer IS_ERR_OR_NULL over manual NULL check
module: Prefer IS_ERR_OR_NULL over manual NULL check
sound: Prefer IS_ERR_OR_NULL over manual NULL check
kvm: Prefer IS_ERR_OR_NULL over manual NULL check
apparmor: Prefer IS_ERR_OR_NULL over manual NULL check
lib/test: Prefer IS_ERR_OR_NULL over manual NULL check
md: Prefer IS_ERR_OR_NULL over manual NULL check
net/ipv6: Prefer IS_ERR_OR_NULL over manual NULL check
net/9p: Prefer IS_ERR_OR_NULL over manual NULL check
net/bluetooth: Prefer IS_ERR_OR_NULL over manual NULL check
net/core: Prefer IS_ERR_OR_NULL over manual NULL check
net/netlink: Prefer IS_ERR_OR_NULL over manual NULL check
net/sched: Prefer IS_ERR_OR_NULL over manual NULL check
net/sctp: Prefer IS_ERR_OR_NULL over manual NULL check
net/sunrpc: Prefer IS_ERR_OR_NULL over manual NULL check
net/tipc: Prefer IS_ERR_OR_NULL over manual NULL check
net/wireless: Prefer IS_ERR_OR_NULL over manual NULL check
mm: Prefer IS_ERR_OR_NULL over manual NULL check
arch/arm: Prefer IS_ERR_OR_NULL over manual NULL check
arch/mips: Prefer IS_ERR_OR_NULL over manual NULL check
arch/sh: Prefer IS_ERR_OR_NULL over manual NULL check
drm: Prefer IS_ERR_OR_NULL over manual NULL check
net: Prefer IS_ERR_OR_NULL over manual NULL check
irqchip: Prefer IS_ERR_OR_NULL over manual NULL check
phy: Prefer IS_ERR_OR_NULL over manual NULL check
pinctrl: Prefer IS_ERR_OR_NULL over manual NULL check
pmdomain: Prefer IS_ERR_OR_NULL over manual NULL check
s390: Prefer IS_ERR_OR_NULL over manual NULL check
target: Prefer IS_ERR_OR_NULL over manual NULL check
thermal: Prefer IS_ERR_OR_NULL over manual NULL check
vfio: Prefer IS_ERR_OR_NULL over manual NULL check
nfc: Prefer IS_ERR_OR_NULL over manual NULL check
mtd: Prefer IS_ERR_OR_NULL over manual NULL check
media: Prefer IS_ERR_OR_NULL over manual NULL check
iommu: Prefer IS_ERR_OR_NULL over manual NULL check
leds: Prefer IS_ERR_OR_NULL over manual NULL check
gpib: Prefer IS_ERR_OR_NULL over manual NULL check
hyperv: Prefer IS_ERR_OR_NULL over manual NULL check
aoe: Prefer IS_ERR_OR_NULL over manual NULL check
interconnect: Prefer IS_ERR_OR_NULL over manual NULL check
clk: Prefer IS_ERR_OR_NULL over manual NULL check
reset: Prefer IS_ERR_OR_NULL over manual NULL check
arch/x86: Prefer IS_ERR_OR_NULL over manual NULL check
debugobjects: Drop likely() around !IS_ERR_OR_NULL()
Input alps: Drop unlikely() around IS_ERR_OR_NULL()
file: Drop unlikely() around IS_ERR_OR_NULL()
arch/arm/common/bL_switcher.c | 2 +-
arch/mips/lantiq/clk.c | 2 +-
arch/sh/mm/ioremap.c | 2 +-
arch/x86/kernel/callthunks.c | 2 +-
arch/x86/kernel/irq.c | 2 +-
drivers/block/aoe/aoecmd.c | 2 +-
drivers/clk/clk.c | 4 +-
drivers/clocksource/timer-pxa.c | 2 +-
drivers/gpib/common/iblib.c | 2 +-
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +-
drivers/gpu/drm/drm_sysfs.c | 2 +-
drivers/gpu/drm/i915/gvt/scheduler.c | 4 +-
drivers/gpu/drm/radeon/radeon_test.c | 2 +-
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 2 +-
drivers/hv/mshv_eventfd.c | 4 +-
drivers/input/mouse/alps.c | 2 +-
drivers/interconnect/core.c | 2 +-
drivers/iommu/omap-iommu.c | 2 +-
drivers/irqchip/irq-gic-v3.c | 2 +-
drivers/irqchip/irq-mvebu-odmi.c | 2 +-
drivers/leds/trigger/ledtrig-tty.c | 2 +-
drivers/md/dm-cache-metadata.c | 2 +-
drivers/md/dm-crypt.c | 4 +-
drivers/media/test-drivers/vimc/vimc-streamer.c | 2 +-
drivers/mtd/nand/raw/gpio.c | 10 +-
drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 2 +-
drivers/net/ethernet/broadcom/tg3.c | 2 +-
.../net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 3 +-
drivers/net/ethernet/intel/ice/devlink/devlink.c | 2 +-
.../ethernet/marvell/prestera/prestera_router.c | 2 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
drivers/net/mdio/mdio-xgene.c | 2 +-
drivers/net/usb/r8152.c | 2 +-
drivers/nfc/trf7970a.c | 2 +-
drivers/phy/phy-core.c | 2 +-
drivers/pinctrl/core.c | 2 +-
drivers/pmdomain/rockchip/pm-domains.c | 2 +-
drivers/reset/core.c | 2 +-
drivers/s390/char/tape_class.c | 2 +-
drivers/target/target_core_fabric_configfs.c | 6 +-
drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
drivers/vfio/vfio_main.c | 2 +-
fs/9p/fid.h | 2 +-
fs/btrfs/inode.c | 2 +-
fs/btrfs/transaction.c | 2 +-
fs/btrfs/tree-log.c | 2 +-
fs/btrfs/uuid-tree.c | 2 +-
fs/ceph/dir.c | 2 +-
fs/ceph/snap.c | 2 +-
fs/erofs/zdata.c | 2 +-
fs/ext4/fast_commit.c | 2 +-
fs/ext4/mballoc.c | 2 +-
fs/ext4/namei.c | 2 +-
fs/ext4/symlink.c | 2 +-
fs/fuse/dir.c | 2 +-
fs/gfs2/glock.c | 2 +-
fs/ntfs3/fsntfs.c | 8 +-
fs/pstore/zone.c | 2 +-
fs/quota/quota.c | 2 +-
fs/seq_file.c | 4 +-
fs/smb/client/cifsglob.h | 2 +-
fs/smb/client/connect.c | 2 +-
fs/smb/client/readdir.c | 2 +-
fs/squashfs/cache.c | 2 +-
include/linux/file.h | 2 +-
include/net/9p/client.h | 2 +-
kernel/module/main.c | 2 +-
kernel/sched/ext.c | 2 +-
kernel/trace/fprobe.c | 2 +-
kernel/trace/kprobe_event_gen_test.c | 2 +-
kernel/trace/trace_events_hist.c | 2 +-
lib/debugobjects.c | 2 +-
lib/test_firmware.c | 2 +-
lib/test_kmod.c | 4 +-
mm/kmemleak.c | 16 +--
net/9p/trans_rdma.c | 8 +-
net/bluetooth/mgmt.c | 6 +-
net/core/xdp.c | 2 +-
net/ipv6/ila/ila_xlat.c | 2 +-
net/ipv6/ndisc.c | 2 +-
net/netlink/af_netlink.c | 2 +-
net/sched/cls_api.c | 6 +-
net/sctp/socket.c | 2 +-
net/sunrpc/xprtrdma/svc_rdma_transport.c | 12 +-
net/tipc/socket.c | 2 +-
net/wireless/reg.c | 2 +-
scripts/coccinelle/api/is_err_or_null.cocci | 125 +++++++++++++++++++++
security/apparmor/apparmorfs.c | 2 +-
sound/soc/samsung/i2s.c | 4 +-
sound/soc/xtensa/xtfpga-i2s.c | 2 +-
virt/kvm/eventfd.c | 4 +-
91 files changed, 251 insertions(+), 127 deletions(-)
---
base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
change-id: 20260305-b4-is_err_or_null-59998a7d03c4
Best regards,
--
Philipp Hahn <phahn-oss@avm.de>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v4 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Neil Armstrong @ 2026-03-18 15:07 UTC (permalink / raw)
To: Bryan O'Donoghue, 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: <80ddc2b4-d6f8-4e8d-a45e-69c05d100aa2@linaro.org>
On 3/18/26 14:17, Bryan O'Donoghue wrote:
> On 18/03/2026 10:15, Neil Armstrong wrote:
>>> + /*
>>> + * phy_configure_opts_mipi_dphy.lanes starts from zero to
>>> + * the maximum number of enabled lanes.
>>> + *
>>> + * TODO: add support for bitmask of enabled lanes and polarities
>>> + * of those lanes to the phy_configure_opts_mipi_dphy struct.
>>> + * For now take the polarities as zero and the position as fixed
>>> + * this is fine as no current upstream implementation maps otherwise.
>>> + */
>>
>> This is wrong since you loose the lanes mapping defined in DT, which is still in CAMSS
>> but is a PHY property. The lanes layout is not a property of the CSI controller,
>> CSI controller only need to know the lanes count, and not the layout.
>
> Lane layout is a PHY concern but, the PHY API gives us phy_configure_opts_mipi_dphy which should be extended to provide layout and polarity. This would then be of benefit to more than just qcom/camss.
Why ? the only concern between a controller and a PHY is the lane count to calculate the bandwidth, the actual pin layout is certainly not a controller concern.
>
> Right now none of the CAMSS users for this driver depend on any other mapping and I propose a separate series to fix phy_configure_opts_mipi_dphy rather than introduce data-lanes to DPHY.
None of the upstream users of camss.
The problem is even larger, as you replied in [1], the csiphy is still exposed as a media element from the CAMSS driver, this means this driver is not complete,
it should be a media driver entirely with eventually an internal PHY aux driver, but this would be entirely implementation specific.
Either the PHY is standalone and the PHY consumer only calls phy_open/init/configure/power_on/power_off/exit, otherwise it's not a fully standaline PHY but a composite device like here.
I propose that you write a proper media driver for the qcom csiphy, which eventually spins a PHY driver as an aux device.
Neil
>
> ---
> bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 7/7] arm64: dts: ti: k3-j722s-main: use J722S compatible strings for SGMII support
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
Update WIZ, gmii-sel and CPSW3G to use the J722S-specific compatible
strings.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
arch/arm64/boot/dts/ti/k3-j722s-main.dtsi | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi
index 9ee5d0c8ffd1e..be7e533e6c38a 100644
--- a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi
@@ -18,7 +18,7 @@ serdes_refclk: clk-0 {
&cbass_main {
serdes_wiz0: phy@f000000 {
- compatible = "ti,am64-wiz-10g";
+ compatible = "ti,j722s-wiz-10g";
ranges = <0x0f000000 0x0 0x0f000000 0x00010000>;
#address-cells = <1>;
#size-cells = <1>;
@@ -56,7 +56,7 @@ serdes0: serdes@f000000 {
};
serdes_wiz1: phy@f010000 {
- compatible = "ti,am64-wiz-10g";
+ compatible = "ti,j722s-wiz-10g";
ranges = <0x0f010000 0x0 0x0f010000 0x00010000>;
#address-cells = <1>;
#size-cells = <1>;
@@ -451,6 +451,14 @@ pcie0_ctrl: pcie0-ctrl@4070 {
};
};
+&cpsw3g {
+ compatible = "ti,j722s-cpsw-nuss";
+};
+
+&phy_gmii_sel {
+ compatible = "ti,j722s-phy-gmii-sel";
+};
+
&oc_sram {
reg = <0x00 0x70000000 0x00 0x40000>;
ranges = <0x00 0x00 0x70000000 0x40000>;
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 0/7] J722S SGMII support
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
The J722S CPSW and SERDES are very similar to the variants found on the
AM64, but they additionally support SGMII. Introduce new compatible
strings for the J722S to add this support to the drivers.
This is a prerequisite for the Single-Pair Ethernet interface of the
TQ-Systems MBa67xx baseboard for the TQMa67xx SoM, which will be
submitted separately.
Nora Schiffer (7):
dt-bindings: phy: ti: phy-j721e-wiz: Add ti,j722s-wiz-10g compatible
dt-bindings: phy: ti: phy-gmii-sel: Add ti,j722s-phy-gmii-sel
compatible
dt-bindings: net: ti: k3-am654-cpsw-nuss: Add ti,j722s-cpsw-nuss
compatible
phy: ti: phy-j721e-wiz: add support for J722S SoC family
phy: ti: gmii-sel: add support for J722S SoC family
net: ethernet: ti: am65-cpsw: add support for J722S SoC family
arm64: dts: ti: k3-j722s-main: use J722S compatible strings for SGMII
support
.../bindings/net/ti,k3-am654-cpsw-nuss.yaml | 1 +
.../bindings/phy/ti,phy-gmii-sel.yaml | 1 +
.../bindings/phy/ti,phy-j721e-wiz.yaml | 1 +
arch/arm64/boot/dts/ti/k3-j722s-main.dtsi | 12 ++++++++--
drivers/net/ethernet/ti/am65-cpsw-nuss.c | 8 +++++++
drivers/phy/ti/phy-gmii-sel.c | 11 +++++++++
drivers/phy/ti/phy-j721e-wiz.c | 24 +++++++++++++++++++
7 files changed, 56 insertions(+), 2 deletions(-)
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 5/7] phy: ti: gmii-sel: add support for J722S SoC family
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
The J722S gmii-sel is mostly identical to the AM64's, but additionally
supports SGMII.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
drivers/phy/ti/phy-gmii-sel.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index 6213c2b6005a5..4e242b1892334 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -251,6 +251,13 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
.regfields = phy_gmii_sel_fields_am654,
};
+static const
+struct phy_gmii_sel_soc_data phy_gmii_sel_soc_j722s = {
+ .use_of_data = true,
+ .regfields = phy_gmii_sel_fields_am654,
+ .extra_modes = BIT(PHY_INTERFACE_MODE_SGMII),
+};
+
static const
struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = {
.use_of_data = true,
@@ -307,6 +314,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
.compatible = "ti,am654-phy-gmii-sel",
.data = &phy_gmii_sel_soc_am654,
},
+ {
+ .compatible = "ti,j722s-phy-gmii-sel",
+ .data = &phy_gmii_sel_soc_j722s,
+ },
{
.compatible = "ti,j7200-cpsw5g-phy-gmii-sel",
.data = &phy_gmii_sel_cpsw5g_soc_j7200,
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 6/7] net: ethernet: ti: am65-cpsw: add support for J722S SoC family
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
The J722S CPSW3G is mostly identical to the AM64's, but additionally
supports SGMII.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
drivers/net/ethernet/ti/am65-cpsw-nuss.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index d9400599e80a4..fc57d5e6edf4c 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -3468,6 +3468,13 @@ static const struct am65_cpsw_pdata am64x_cpswxg_pdata = {
.fdqring_mode = K3_RINGACC_RING_MODE_RING,
};
+static const struct am65_cpsw_pdata j722s_cpswxg_pdata = {
+ .quirks = AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ | AM64_CPSW_QUIRK_CUT_THRU,
+ .ale_dev_id = "am64-cpswxg",
+ .fdqring_mode = K3_RINGACC_RING_MODE_RING,
+ .extra_modes = BIT(PHY_INTERFACE_MODE_SGMII),
+};
+
static const struct am65_cpsw_pdata j7200_cpswxg_pdata = {
.quirks = 0,
.ale_dev_id = "am64-cpswxg",
@@ -3495,6 +3502,7 @@ static const struct of_device_id am65_cpsw_nuss_of_mtable[] = {
{ .compatible = "ti,am654-cpsw-nuss", .data = &am65x_sr1_0},
{ .compatible = "ti,j721e-cpsw-nuss", .data = &j721e_pdata},
{ .compatible = "ti,am642-cpsw-nuss", .data = &am64x_cpswxg_pdata},
+ { .compatible = "ti,j722s-cpsw-nuss", .data = &j722s_cpswxg_pdata},
{ .compatible = "ti,j7200-cpswxg-nuss", .data = &j7200_cpswxg_pdata},
{ .compatible = "ti,j721e-cpswxg-nuss", .data = &j721e_cpswxg_pdata},
{ .compatible = "ti,j784s4-cpswxg-nuss", .data = &j784s4_cpswxg_pdata},
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 4/7] phy: ti: phy-j721e-wiz: add support for J722S SoC family
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
The J722S WIZ is mostly identical to the AM64's, but additionally supports
SGMII.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
drivers/phy/ti/phy-j721e-wiz.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 6b584706b913a..7531a8a049123 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -331,6 +331,7 @@ enum wiz_type {
J721E_WIZ_16G,
J721E_WIZ_10G, /* Also for J7200 SR1.0 */
AM64_WIZ_10G,
+ J722S_WIZ_10G,
J7200_WIZ_10G, /* J7200 SR2.0 */
J784S4_WIZ_10G,
J721S2_WIZ_10G,
@@ -1020,6 +1021,7 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node)
switch (wiz->type) {
case AM64_WIZ_10G:
+ case J722S_WIZ_10G:
case J7200_WIZ_10G:
case J784S4_WIZ_10G:
case J721S2_WIZ_10G:
@@ -1089,6 +1091,7 @@ static void wiz_clock_init(struct wiz *wiz)
switch (wiz->type) {
case AM64_WIZ_10G:
+ case J722S_WIZ_10G:
case J7200_WIZ_10G:
switch (rate) {
case REF_CLK_100MHZ:
@@ -1158,6 +1161,7 @@ static int wiz_clock_probe(struct wiz *wiz, struct device_node *node)
switch (wiz->type) {
case AM64_WIZ_10G:
+ case J722S_WIZ_10G:
case J7200_WIZ_10G:
case J784S4_WIZ_10G:
case J721S2_WIZ_10G:
@@ -1246,6 +1250,14 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane)
if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII)
return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2);
break;
+
+ case J722S_WIZ_10G:
+ if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE)
+ return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1);
+ if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII)
+ return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2);
+ break;
+
default:
return 0;
}
@@ -1350,6 +1362,15 @@ static struct wiz_data am64_10g_data = {
.clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
};
+static struct wiz_data j722s_10g_data = {
+ .type = J722S_WIZ_10G,
+ .pll0_refclk_mux_sel = &pll0_refclk_mux_sel,
+ .pll1_refclk_mux_sel = &pll1_refclk_mux_sel,
+ .refclk_dig_sel = &refclk_dig_sel_10g,
+ .clk_mux_sel = clk_mux_sel_10g,
+ .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
+};
+
static struct wiz_data j7200_pg2_10g_data = {
.type = J7200_WIZ_10G,
.pll0_refclk_mux_sel = &sup_pll0_refclk_mux_sel,
@@ -1389,6 +1410,9 @@ static const struct of_device_id wiz_id_table[] = {
{
.compatible = "ti,am64-wiz-10g", .data = &am64_10g_data,
},
+ {
+ .compatible = "ti,j722s-wiz-10g", .data = &j722s_10g_data,
+ },
{
.compatible = "ti,j7200-wiz-10g", .data = &j7200_pg2_10g_data,
},
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 2/7] dt-bindings: phy: ti: phy-gmii-sel: Add ti,j722s-phy-gmii-sel compatible
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
The J722S gmii-sel is mostly identical to the AM64's, but additionally
supports SGMII.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
index be41b4547ec6d..fa3f3ad9fcc3e 100644
--- a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
@@ -55,6 +55,7 @@ properties:
- ti,am654-phy-gmii-sel
- ti,j7200-cpsw5g-phy-gmii-sel
- ti,j721e-cpsw9g-phy-gmii-sel
+ - ti,j722s-phy-gmii-sel
- ti,j784s4-cpsw9g-phy-gmii-sel
reg:
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 1/7] dt-bindings: phy: ti: phy-j721e-wiz: Add ti,j722s-wiz-10g compatible
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
The J722S WIZ is mostly identical to the AM64's, but additionally supports
SGMII.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
index 3f16ff14484d2..e476ff1991b13 100644
--- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
@@ -17,6 +17,7 @@ properties:
- ti,j721e-wiz-10g
- ti,j721s2-wiz-10g
- ti,am64-wiz-10g
+ - ti,j722s-wiz-10g
- ti,j7200-wiz-10g
- ti,j784s4-wiz-10g
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 3/7] dt-bindings: net: ti: k3-am654-cpsw-nuss: Add ti,j722s-cpsw-nuss compatible
From: Nora Schiffer @ 2026-03-18 14:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo
Cc: Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux, Nora Schiffer
In-Reply-To: <cover.1773751309.git.nora.schiffer@ew.tq-group.com>
The J722S CPSW3G is mostly identical to the AM64's, but additionally
supports SGMII.
Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
---
Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml b/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml
index a959c1d7e643a..9ab8237c7f79e 100644
--- a/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml
+++ b/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml
@@ -59,6 +59,7 @@ properties:
- ti,j7200-cpswxg-nuss
- ti,j721e-cpsw-nuss
- ti,j721e-cpswxg-nuss
+ - ti,j722s-cpsw-nuss
- ti,j784s4-cpswxg-nuss
reg:
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
https://www.tq-group.com/
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* RE: [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
From: Biju Das @ 2026-03-18 13:25 UTC (permalink / raw)
To: geert
Cc: biju.das.au, Vinod Koul, Neil Armstrong,
linux-phy@lists.infradead.org, linux-kernel@vger.kernel.org,
Geert Uytterhoeven, Prabhakar Mahadev Lad,
linux-renesas-soc@vger.kernel.org, Pavel Machek
In-Reply-To: <CAMuHMdXph-ns=8hHWoDKoNgUiGQ4=A9+aASim6qrLDdAE_mPMw@mail.gmail.com>
Hi Geert,
> -----Original Message-----
> From: Geert Uytterhoeven <geert@linux-m68k.org>
> Sent: 18 March 2026 13:14
> Subject: Re: [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
>
> Hi Biju,
>
> On Wed, 18 Mar 2026 at 14:08, Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > > From: Geert Uytterhoeven <geert@linux-m68k.org> On Wed, 18 Mar 2026
> > > at 13:01, Biju <biju.das.au@gmail.com> wrote:
> > > > From: Biju Das <biju.das.jz@bp.renesas.com>
> > > >
> > > > Fix a malformed MODULE_AUTHOR macro in the RZ/G3E USB3.0 PHY
> > > > driver where the author's name and opening angle bracket were
> > > > missing, leaving only the email address with a stray closing >.
> > > > Correct it to the standard Name <email> format.
> > > >
> > > > Reported-by: Pavel Machek <pavel@nabladev.com>
> > > > Closes:
> > > > https://lore.kernel.org/cip-dev/abp4Y2FVspUgEpCT@duo.ucw.cz/T/#ma8
> > > > 0454
> > > > df129c8cfcbe48d75f3b4abe697925c6f8
> > >
> > > The "/T/#..." suffix is not really needed.
>
> And after sending, I realized the "/cip-dev" part is also not needed.
Thanks, next time will trim this as well.
Cheers,
Biju
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v4 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Bryan O'Donoghue @ 2026-03-18 13:17 UTC (permalink / raw)
To: Neil Armstrong, 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: <3f11de22-b729-4d06-b6c8-18e649e1979c@linaro.org>
On 18/03/2026 10:15, Neil Armstrong wrote:
>> + /*
>> + * phy_configure_opts_mipi_dphy.lanes starts from zero to
>> + * the maximum number of enabled lanes.
>> + *
>> + * TODO: add support for bitmask of enabled lanes and polarities
>> + * of those lanes to the phy_configure_opts_mipi_dphy struct.
>> + * For now take the polarities as zero and the position as fixed
>> + * this is fine as no current upstream implementation maps
>> otherwise.
>> + */
>
> This is wrong since you loose the lanes mapping defined in DT, which is
> still in CAMSS
> but is a PHY property. The lanes layout is not a property of the CSI
> controller,
> CSI controller only need to know the lanes count, and not the layout.
Lane layout is a PHY concern but, the PHY API gives us
phy_configure_opts_mipi_dphy which should be extended to provide layout
and polarity. This would then be of benefit to more than just qcom/camss.
Right now none of the CAMSS users for this driver depend on any other
mapping and I propose a separate series to fix
phy_configure_opts_mipi_dphy rather than introduce data-lanes to DPHY.
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
From: Geert Uytterhoeven @ 2026-03-18 13:13 UTC (permalink / raw)
To: Biju Das
Cc: biju.das.au, Vinod Koul, Neil Armstrong,
linux-phy@lists.infradead.org, linux-kernel@vger.kernel.org,
Geert Uytterhoeven, Prabhakar Mahadev Lad,
linux-renesas-soc@vger.kernel.org, Pavel Machek
In-Reply-To: <TY3PR01MB11346D89F6F7C332FEF0D08B3864EA@TY3PR01MB11346.jpnprd01.prod.outlook.com>
Hi Biju,
On Wed, 18 Mar 2026 at 14:08, Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > From: Geert Uytterhoeven <geert@linux-m68k.org>
> > On Wed, 18 Mar 2026 at 13:01, Biju <biju.das.au@gmail.com> wrote:
> > > From: Biju Das <biju.das.jz@bp.renesas.com>
> > >
> > > Fix a malformed MODULE_AUTHOR macro in the RZ/G3E USB3.0 PHY driver
> > > where the author's name and opening angle bracket were missing,
> > > leaving only the email address with a stray closing >. Correct it to
> > > the standard Name <email> format.
> > >
> > > Reported-by: Pavel Machek <pavel@nabladev.com>
> > > Closes:
> > > https://lore.kernel.org/cip-dev/abp4Y2FVspUgEpCT@duo.ucw.cz/T/#ma80454
> > > df129c8cfcbe48d75f3b4abe697925c6f8
> >
> > The "/T/#..." suffix is not really needed.
And after sending, I realized the "/cip-dev" part is also not needed.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* RE: [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
From: Biju Das @ 2026-03-18 13:08 UTC (permalink / raw)
To: geert, biju.das.au
Cc: Vinod Koul, Neil Armstrong, linux-phy@lists.infradead.org,
linux-kernel@vger.kernel.org, Geert Uytterhoeven,
Prabhakar Mahadev Lad, linux-renesas-soc@vger.kernel.org,
Pavel Machek
In-Reply-To: <CAMuHMdW1ROF3VdKzXVNeKtPZPEwX4MHD-kqdunrNYKBprPgPWw@mail.gmail.com>
Hi Geert,
Thanks for the feedback.
> -----Original Message-----
> From: Geert Uytterhoeven <geert@linux-m68k.org>
> Sent: 18 March 2026 12:48
> Subject: Re: [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
>
> On Wed, 18 Mar 2026 at 13:01, Biju <biju.das.au@gmail.com> wrote:
> > From: Biju Das <biju.das.jz@bp.renesas.com>
> >
> > Fix a malformed MODULE_AUTHOR macro in the RZ/G3E USB3.0 PHY driver
> > where the author's name and opening angle bracket were missing,
> > leaving only the email address with a stray closing >. Correct it to
> > the standard Name <email> format.
> >
> > Reported-by: Pavel Machek <pavel@nabladev.com>
> > Closes:
> > https://lore.kernel.org/cip-dev/abp4Y2FVspUgEpCT@duo.ucw.cz/T/#ma80454
> > df129c8cfcbe48d75f3b4abe697925c6f8
>
> The "/T/#..." suffix is not really needed.
Thanks, will take care next time.
Cheers,
Biju
>
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But when I'm talking to
> journalists I just say "programmer" or something like that.
> -- Linus Torvalds
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
From: Geert Uytterhoeven @ 2026-03-18 12:47 UTC (permalink / raw)
To: Biju
Cc: Vinod Koul, Biju Das, Neil Armstrong, linux-phy, linux-kernel,
Geert Uytterhoeven, Prabhakar Mahadev Lad, linux-renesas-soc,
Pavel Machek
In-Reply-To: <20260318120102.226118-1-biju.das.jz@bp.renesas.com>
On Wed, 18 Mar 2026 at 13:01, Biju <biju.das.au@gmail.com> wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> Fix a malformed MODULE_AUTHOR macro in the RZ/G3E USB3.0 PHY driver where
> the author's name and opening angle bracket were missing, leaving only the
> email address with a stray closing >. Correct it to the standard Name
> <email> format.
>
> Reported-by: Pavel Machek <pavel@nabladev.com>
> Closes: https://lore.kernel.org/cip-dev/abp4Y2FVspUgEpCT@duo.ucw.cz/T/#ma80454df129c8cfcbe48d75f3b4abe697925c6f8
The "/T/#..." suffix is not really needed.
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string
From: Biju @ 2026-03-18 12:00 UTC (permalink / raw)
To: Vinod Koul
Cc: Biju Das, Neil Armstrong, linux-phy, linux-kernel,
Geert Uytterhoeven, Prabhakar Mahadev Lad, Biju Das,
linux-renesas-soc, Pavel Machek
From: Biju Das <biju.das.jz@bp.renesas.com>
Fix a malformed MODULE_AUTHOR macro in the RZ/G3E USB3.0 PHY driver where
the author's name and opening angle bracket were missing, leaving only the
email address with a stray closing >. Correct it to the standard Name
<email> format.
Reported-by: Pavel Machek <pavel@nabladev.com>
Closes: https://lore.kernel.org/cip-dev/abp4Y2FVspUgEpCT@duo.ucw.cz/T/#ma80454df129c8cfcbe48d75f3b4abe697925c6f8
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
drivers/phy/renesas/phy-rzg3e-usb3.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/phy/renesas/phy-rzg3e-usb3.c b/drivers/phy/renesas/phy-rzg3e-usb3.c
index 6b3453ea0004..030c600a53e6 100644
--- a/drivers/phy/renesas/phy-rzg3e-usb3.c
+++ b/drivers/phy/renesas/phy-rzg3e-usb3.c
@@ -256,4 +256,4 @@ module_platform_driver(rzg3e_phy_usb3_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Renesas RZ/G3E USB3.0 PHY Driver");
-MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.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
* Re: [PATCH v4 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Neil Armstrong @ 2026-03-18 10:15 UTC (permalink / raw)
To: Bryan O'Donoghue, 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: <20260315-x1e-csi2-phy-v4-2-90c09203888d@linaro.org>
On 3/16/26 00:52, 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. At
> the moment we follow the assignment of lane positions - the bitmap of
> physical input lanes to logical lane numbers as a linear list per the
> existing DPHY @lanes data-member.
>
> This is fine for us in upstream at the moment since we also map the lanes
> contiguously but, our hardware can support different lane mappings so we
> should in the future extend out the DPHY structure to capture the mapping.
>
> 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 | 364 +++++++++++++++++++++
> drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c | 289 ++++++++++++++++
> drivers/phy/qualcomm/phy-qcom-mipi-csi2.h | 101 ++++++
> 6 files changed, 783 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 62ccdc72384d4..fe19722355d94 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21542,6 +21542,17 @@ S: Maintained
> F: Documentation/devicetree/bindings/media/qcom,*-iris.yaml
> F: drivers/media/platform/qcom/iris/
>
> +QUALCOMM MIPI CSI2 PHY DRIVER
> +M: Bryan O'Donoghue <bod@kernel.org>
> +L: linux-phy@lists.infradead.org
> +L: linux-media@vger.kernel.org
> +L: linux-arm-msm@vger.kernel.org
> +S: Supported
> +F: Documentation/devicetree/bindings/phy/qcom,*-csi2-phy.yaml
> +F: drivers/phy/qualcomm/phy-qcom-mipi-csi2*.c
> +F: drivers/phy/qualcomm/phy-qcom-mipi-csi2*.h
> +F: include/dt-bindings/phy/phy-qcom-mipi-csi2*
> +
> QUALCOMM NAND CONTROLLER DRIVER
> M: Manivannan Sadhasivam <mani@kernel.org>
> L: linux-mtd@lists.infradead.org
> diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
> index 60a0ead127fa9..ea33025a40fd0 100644
> --- a/drivers/phy/qualcomm/Kconfig
> +++ b/drivers/phy/qualcomm/Kconfig
> @@ -28,6 +28,19 @@ config PHY_QCOM_EDP
> Enable this driver to support the Qualcomm eDP PHY found in various
> Qualcomm chipsets.
>
> +config PHY_QCOM_MIPI_CSI2
> + tristate "Qualcomm MIPI CSI2 PHY driver"
> + depends on ARCH_QCOM || COMPILE_TEST
> + depends on OF
> + depends on COMMON_CLK
> + select GENERIC_PHY
> + select GENERIC_PHY_MIPI_DPHY
> + help
> + Enable this to support the MIPI CSI2 PHY driver found in various
> + Qualcomm chipsets. This PHY is used to connect MIPI CSI2
> + camera sensors to the CSI Decoder in the Qualcomm Camera Subsystem
> + CAMSS.
> +
> config PHY_QCOM_IPQ4019_USB
> tristate "Qualcomm IPQ4019 USB PHY driver"
> depends on OF && (ARCH_QCOM || COMPILE_TEST)
> diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
> index b71a6a0bed3f1..382cb594b06b6 100644
> --- a/drivers/phy/qualcomm/Makefile
> +++ b/drivers/phy/qualcomm/Makefile
> @@ -6,6 +6,11 @@ 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_M31_USB) += phy-qcom-m31.o
> obj-$(CONFIG_PHY_QCOM_M31_EUSB) += phy-qcom-m31-eusb2.o
> +
> +phy-qcom-mipi-csi2-objs += phy-qcom-mipi-csi2-core.o \
> + phy-qcom-mipi-csi2-3ph-dphy.o
> +obj-$(CONFIG_PHY_QCOM_MIPI_CSI2) += phy-qcom-mipi-csi2.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
> diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
> new file mode 100644
> index 0000000000000..874c5c2cb01c8
> --- /dev/null
> +++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
> @@ -0,0 +1,364 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Qualcomm MSM Camera Subsystem - CSIPHY Module 3phase v1.0
> + *
> + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2016-2025 Linaro Ltd.
> + */
> +
> +#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))
> +
> +/*
> + * 3 phase CSI has 19 common status regs with only 0-10 being used
> + * and 11-18 being reserved.
> + */
> +#define CSI_COMMON_STATUS_NUM 11
> +/*
> + * There are a number of common control registers
> + * The offset to clear the CSIPHY IRQ status starts @ 22
> + * So to clear CSI_COMMON_STATUS0 this is CSI_COMMON_CONTROL22, STATUS1 is
> + * CONTROL23 and so on
> + */
> +#define CSI_CTRL_STATUS_INDEX 22
> +
> +/*
> + * There are 43 COMMON_CTRL registers with regs after # 33 being reserved
> + */
> +#define CSI_CTRL_MAX 33
> +
> +#define CSIPHY_DEFAULT_PARAMS 0
> +#define CSIPHY_SETTLE_CNT_LOWER_BYTE 2
> +#define CSIPHY_SKEW_CAL 7
> +
> +/* 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},
> +
> + {.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},
> +};
> +
> +static inline const struct mipi_csi2phy_device_regs *
> +csi2phy_dev_to_regs(struct mipi_csi2phy_device *csi2phy)
> +{
> + return &csi2phy->soc_cfg->reg_info;
> +}
> +
> +static void phy_qcom_mipi_csi2_hw_version_read(struct mipi_csi2phy_device *csi2phy)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> + u32 tmp;
> +
> + writel(CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 6));
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 12));
> + csi2phy->hw_version = tmp;
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 13));
> + csi2phy->hw_version |= (tmp << 8) & 0xFF00;
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 14));
> + csi2phy->hw_version |= (tmp << 16) & 0xFF0000;
> +
> + tmp = readl_relaxed(csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->common_regs_offset, 15));
> + csi2phy->hw_version |= (tmp << 24) & 0xFF000000;
> +
> + dev_dbg_once(csi2phy->dev, "CSIPHY 3PH HW Version = 0x%08x\n", csi2phy->hw_version);
> +}
> +
> +/*
> + * phy_qcom_mipi_csi2_reset - Perform software reset on CSIPHY module
> + * @phy_qcom_mipi_csi2: CSIPHY device
> + */
> +static void phy_qcom_mipi_csi2_reset(struct mipi_csi2phy_device *csi2phy)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> +
> + writel(CSIPHY_3PH_CMN_CSI_COMMON_CTRL0_PHY_SW_RESET,
> + csi2phy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
> + usleep_range(5000, 8000);
> + writel(0x0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
> +}
> +
> +/*
> + * phy_qcom_mipi_csi2_settle_cnt_calc - Calculate settle count value
> + *
> + * Helper function to calculate settle count value. This is
> + * based on the CSI2 T_hs_settle parameter which in turn
> + * is calculated based on the CSI2 transmitter link frequency.
> + *
> + * Return settle count value or 0 if the CSI2 link frequency
> + * is not available
> + */
> +static u8 phy_qcom_mipi_csi2_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate)
> +{
> + u32 t_hs_prepare_max_ps;
> + u32 timer_period_ps;
> + u32 t_hs_settle_ps;
> + u8 settle_cnt;
> + u32 ui_ps;
> +
> + if (link_freq <= 0)
> + return 0;
> +
> + ui_ps = div_u64(PSEC_PER_SEC, link_freq);
> + ui_ps /= 2;
> + t_hs_prepare_max_ps = 85000 + 6 * ui_ps;
> + t_hs_settle_ps = t_hs_prepare_max_ps;
> +
> + timer_period_ps = div_u64(PSEC_PER_SEC, timer_clk_rate);
> + settle_cnt = t_hs_settle_ps / timer_period_ps - 6;
> +
> + return settle_cnt;
> +}
> +
> +static void
> +phy_qcom_mipi_csi2_gen2_config_lanes(struct mipi_csi2phy_device *csi2phy,
> + u8 settle_cnt)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> + const struct mipi_csi2phy_lane_regs *r = regs->init_seq;
> + int i, array_size = regs->lane_array_size;
> + u32 val;
> +
> + for (i = 0; i < array_size; i++, r++) {
> + switch (r->param_type) {
> + case CSIPHY_SETTLE_CNT_LOWER_BYTE:
> + val = settle_cnt & 0xff;
> + break;
> + case CSIPHY_SKEW_CAL:
> + /* TODO: support application of skew from dt flag */
> + continue;
> + default:
> + val = r->reg_data;
> + break;
> + }
> + writel(val, csi2phy->base + r->reg_addr);
> + if (r->delay_us)
> + udelay(r->delay_us);
> + }
> +}
> +
> +static int phy_qcom_mipi_csi2_lanes_enable(struct mipi_csi2phy_device *csi2phy,
> + struct mipi_csi2phy_stream_cfg *cfg)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> + struct mipi_csi2phy_lanes_cfg *lane_cfg = &cfg->lane_cfg;
> + u8 settle_cnt;
> + u8 val;
> + int i;
> +
> + settle_cnt = phy_qcom_mipi_csi2_settle_cnt_calc(cfg->link_freq, csi2phy->timer_clk_rate);
> +
> + val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE;
> + for (i = 0; i < cfg->num_data_lanes; i++)
> + val |= BIT(lane_cfg->data[i].pos * 2);
> +
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 5));
> +
> + val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B;
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 6));
> +
> + val = 0x02;
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 7));
> +
> + val = 0x00;
> + writel(val, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 0));
> +
> + phy_qcom_mipi_csi2_gen2_config_lanes(csi2phy, settle_cnt);
> +
> + /* IRQ_MASK registers - disable all interrupts */
> + for (i = CSI_COMMON_STATUS_NUM; i < CSI_CTRL_STATUS_INDEX; i++) {
> + writel(0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, i));
> + }
> +
> + return 0;
> +}
> +
> +static void
> +phy_qcom_mipi_csi2_lanes_disable(struct mipi_csi2phy_device *csi2phy,
> + struct mipi_csi2phy_stream_cfg *cfg)
> +{
> + const struct mipi_csi2phy_device_regs *regs = csi2phy_dev_to_regs(csi2phy);
> +
> + writel(0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 5));
> +
> + writel(0, csi2phy->base +
> + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->common_regs_offset, 6));
> +}
> +
> +static const struct mipi_csi2phy_hw_ops phy_qcom_mipi_csi2_ops_3ph_1_0 = {
> + .hw_version_read = phy_qcom_mipi_csi2_hw_version_read,
> + .reset = phy_qcom_mipi_csi2_reset,
> + .lanes_enable = phy_qcom_mipi_csi2_lanes_enable,
> + .lanes_disable = phy_qcom_mipi_csi2_lanes_disable,
> +};
> +
> +static const char * const x1e_clks[] = {
> + "camnoc_axi",
> + "cpas_ahb",
> + "csiphy",
> + "csiphy_timer"
> +};
> +
> +static const char * const x1e_supplies[] = {
> + "vdda-0p8",
> + "vdda-1p2"
> +};
> +
> +static const char * const x1e_genpd_names[] = {
> + "mx",
> + "mmcx",
> +};
> +
> +const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_4nm_x1e = {
> + .ops = &phy_qcom_mipi_csi2_ops_3ph_1_0,
> + .reg_info = {
> + .init_seq = lane_regs_x1e80100,
> + .lane_array_size = ARRAY_SIZE(lane_regs_x1e80100),
> + .common_regs_offset = 0x1000,
> + .generation = GEN2,
> + },
> + .supply_names = (const char **)x1e_supplies,
> + .num_supplies = ARRAY_SIZE(x1e_supplies),
> + .clk_names = (const char **)x1e_clks,
> + .num_clk = ARRAY_SIZE(x1e_clks),
> + .opp_clk = x1e_clks[2],
> + .timer_clk = x1e_clks[3],
> + .genpd_names = (const char **)x1e_genpd_names,
> + .num_genpd_names = ARRAY_SIZE(x1e_genpd_names),
> +};
> diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
> new file mode 100644
> index 0000000000000..b5969ce66cd6d
> --- /dev/null
> +++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
> @@ -0,0 +1,289 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2025, Linaro Ltd.
> + */
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pm_opp.h>
> +#include <linux/phy/phy.h>
> +#include <linux/phy/phy-mipi-dphy.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +
> +#include "phy-qcom-mipi-csi2.h"
> +
> +static int
> +phy_qcom_mipi_csi2_set_clock_rates(struct mipi_csi2phy_device *csi2phy,
> + s64 link_freq)
> +{
> + struct device *dev = csi2phy->dev;
> + unsigned long opp_rate = link_freq / 4;
> + struct dev_pm_opp *opp;
> + long timer_rate;
> + int ret;
> +
> + opp = dev_pm_opp_find_freq_ceil(dev, &opp_rate);
> + if (IS_ERR(opp)) {
> + dev_err(csi2phy->dev, "Couldn't find ceiling for %lld Hz\n",
> + link_freq);
> + return PTR_ERR(opp);
> + }
> +
> + for (int i = 0; i < csi2phy->num_pds; i++) {
> + unsigned int perf = dev_pm_opp_get_required_pstate(opp, i);
> +
> + ret = dev_pm_genpd_set_performance_state(csi2phy->pds[i], perf);
> + if (ret) {
> + dev_err(csi2phy->dev, "Couldn't set perf state %u\n",
> + perf);
> + dev_pm_opp_put(opp);
> + return ret;
> + }
> + }
> + dev_pm_opp_put(opp);
> +
> + ret = dev_pm_opp_set_rate(dev, opp_rate);
> + if (ret) {
> + dev_err(csi2phy->dev, "dev_pm_opp_set_rate() fail\n");
> + return ret;
> + }
> +
> + timer_rate = clk_round_rate(csi2phy->timer_clk, link_freq / 4);
> + if (timer_rate < 0)
> + return timer_rate;
> +
> + ret = clk_set_rate(csi2phy->timer_clk, timer_rate);
> + if (ret)
> + return ret;
> +
> + csi2phy->timer_clk_rate = timer_rate;
> +
> + return 0;
> +}
> +
> +static int phy_qcom_mipi_csi2_configure(struct phy *phy,
> + union phy_configure_opts *opts)
> +{
> + struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
> + struct phy_configure_opts_mipi_dphy *dphy_cfg_opts = &opts->mipi_dphy;
> + struct mipi_csi2phy_stream_cfg *stream_cfg = &csi2phy->stream_cfg;
> + int ret;
> + int i;
> +
> + ret = phy_mipi_dphy_config_validate(dphy_cfg_opts);
> + if (ret)
> + return ret;
> +
> + if (dphy_cfg_opts->lanes < 1 || dphy_cfg_opts->lanes > CSI2_MAX_DATA_LANES)
> + return -EINVAL;
> +
> + stream_cfg->combo_mode = 0;
> + stream_cfg->link_freq = dphy_cfg_opts->hs_clk_rate;
> + stream_cfg->num_data_lanes = dphy_cfg_opts->lanes;
> +
> + /*
> + * phy_configure_opts_mipi_dphy.lanes starts from zero to
> + * the maximum number of enabled lanes.
> + *
> + * TODO: add support for bitmask of enabled lanes and polarities
> + * of those lanes to the phy_configure_opts_mipi_dphy struct.
> + * For now take the polarities as zero and the position as fixed
> + * this is fine as no current upstream implementation maps otherwise.
> + */
This is wrong since you loose the lanes mapping defined in DT, which is still in CAMSS
but is a PHY property. The lanes layout is not a property of the CSI controller,
CSI controller only need to know the lanes count, and not the layout.
> + for (i = 0; i < stream_cfg->num_data_lanes; i++) {
> + stream_cfg->lane_cfg.data[i].pol = 0;
> + stream_cfg->lane_cfg.data[i].pos = i;
> + }
> +
> + stream_cfg->lane_cfg.clk.pol = 0;
> + stream_cfg->lane_cfg.clk.pos = 7;
> +
> + return 0;
> +}
> +
> +static int phy_qcom_mipi_csi2_power_on(struct phy *phy)
> +{
> + struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
> + const struct mipi_csi2phy_hw_ops *ops = csi2phy->soc_cfg->ops;
> + struct device *dev = &phy->dev;
> + int ret;
> +
> + ret = regulator_bulk_enable(csi2phy->soc_cfg->num_supplies,
> + csi2phy->supplies);
> + if (ret)
> + return ret;
> +
> + ret = phy_qcom_mipi_csi2_set_clock_rates(csi2phy, csi2phy->stream_cfg.link_freq);
> + if (ret)
> + goto poweroff_phy;
> +
> + ret = clk_bulk_prepare_enable(csi2phy->soc_cfg->num_clk,
> + csi2phy->clks);
> + if (ret) {
> + dev_err(dev, "failed to enable clocks, %d\n", ret);
> + goto poweroff_phy;
> + }
> +
> + ops->reset(csi2phy);
> +
> + ops->hw_version_read(csi2phy);
> +
> + return ops->lanes_enable(csi2phy, &csi2phy->stream_cfg);
> +
> +poweroff_phy:
> + regulator_bulk_disable(csi2phy->soc_cfg->num_supplies,
> + csi2phy->supplies);
> +
> + return ret;
> +}
> +
> +static int phy_qcom_mipi_csi2_power_off(struct phy *phy)
> +{
> + struct mipi_csi2phy_device *csi2phy = phy_get_drvdata(phy);
> + int i;
> +
> + for (int i = 0; i < csi2phy->num_pds; i++)
> + dev_pm_genpd_set_performance_state(csi2phy->pds[i], 0);
> +
> + clk_bulk_disable_unprepare(csi2phy->soc_cfg->num_clk,
> + csi2phy->clks);
> + regulator_bulk_disable(csi2phy->soc_cfg->num_supplies,
> + csi2phy->supplies);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops phy_qcom_mipi_csi2_ops = {
> + .configure = phy_qcom_mipi_csi2_configure,
> + .power_on = phy_qcom_mipi_csi2_power_on,
> + .power_off = phy_qcom_mipi_csi2_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static int phy_qcom_mipi_csi2_probe(struct platform_device *pdev)
> +{
> + unsigned int i, num_clk, num_supplies, num_pds;
> + struct mipi_csi2phy_device *csi2phy;
> + struct phy_provider *phy_provider;
> + struct device *dev = &pdev->dev;
> + struct phy *generic_phy;
> + int ret;
> +
> + csi2phy = devm_kzalloc(dev, sizeof(*csi2phy), GFP_KERNEL);
> + if (!csi2phy)
> + return -ENOMEM;
> +
> + csi2phy->dev = dev;
> + csi2phy->soc_cfg = device_get_match_data(&pdev->dev);
> +
> + if (!csi2phy->soc_cfg)
> + return -EINVAL;
> +
> + num_clk = csi2phy->soc_cfg->num_clk;
> + csi2phy->clks = devm_kzalloc(dev, sizeof(*csi2phy->clks) * num_clk, GFP_KERNEL);
> + if (!csi2phy->clks)
> + return -ENOMEM;
> +
> + num_pds = csi2phy->soc_cfg->num_genpd_names;
> + if (!num_pds)
> + return -EINVAL;
> +
> + csi2phy->pds = devm_kzalloc(dev, sizeof(*csi2phy->pds) * num_pds, GFP_KERNEL);
> + if (!csi2phy->pds)
> + return -ENOMEM;
> +
> + for (i = 0; i < num_pds; i++) {
> + csi2phy->pds[i] = dev_pm_domain_attach_by_name(dev,
> + csi2phy->soc_cfg->genpd_names[i]);
> + if (IS_ERR(csi2phy->pds[i])) {
> + return dev_err_probe(dev, PTR_ERR(csi2phy->pds[i]),
> + "Failed to attach %s\n",
> + csi2phy->soc_cfg->genpd_names[i]);
> + }
> + }
> + csi2phy->num_pds = num_pds;
> +
> + for (i = 0; i < num_clk; i++)
> + csi2phy->clks[i].id = csi2phy->soc_cfg->clk_names[i];
> +
> + ret = devm_clk_bulk_get(dev, num_clk, csi2phy->clks);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to get clocks\n");
> +
> + csi2phy->timer_clk = devm_clk_get(dev, csi2phy->soc_cfg->timer_clk);
> + if (IS_ERR(csi2phy->timer_clk)) {
> + return dev_err_probe(dev, PTR_ERR(csi2phy->timer_clk),
> + "Failed to get timer clock\n");
> + }
> +
> + ret = devm_pm_opp_set_clkname(dev, csi2phy->soc_cfg->opp_clk);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to set opp clkname\n");
> +
> + ret = devm_pm_opp_of_add_table(dev);
> + if (ret && ret != -ENODEV)
> + return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");
> +
> + num_supplies = csi2phy->soc_cfg->num_supplies;
> + csi2phy->supplies = devm_kzalloc(dev, sizeof(*csi2phy->supplies) * num_supplies,
> + GFP_KERNEL);
> + if (!csi2phy->supplies)
> + return -ENOMEM;
> +
> + for (i = 0; i < num_supplies; i++)
> + csi2phy->supplies[i].supply = csi2phy->soc_cfg->supply_names[i];
> +
> + ret = devm_regulator_bulk_get(dev, num_supplies, csi2phy->supplies);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to get regulator supplies\n");
> +
> + csi2phy->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(csi2phy->base))
> + return PTR_ERR(csi2phy->base);
> +
> + generic_phy = devm_phy_create(dev, NULL, &phy_qcom_mipi_csi2_ops);
> + if (IS_ERR(generic_phy)) {
> + ret = PTR_ERR(generic_phy);
> + return dev_err_probe(dev, ret, "failed to create phy\n");
> + }
> + csi2phy->phy = generic_phy;
> +
> + phy_set_drvdata(generic_phy, csi2phy);
> +
> + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> + if (!IS_ERR(phy_provider))
> + dev_dbg(dev, "Registered MIPI CSI2 PHY device\n");
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_qcom_mipi_csi2_of_match_table[] = {
> + { .compatible = "qcom,x1e80100-csi2-phy", .data = &mipi_csi2_dphy_4nm_x1e },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, phy_qcom_mipi_csi2_of_match_table);
> +
> +static struct platform_driver phy_qcom_mipi_csi2_driver = {
> + .probe = phy_qcom_mipi_csi2_probe,
> + .driver = {
> + .name = "qcom-mipi-csi2-phy",
> + .of_match_table = phy_qcom_mipi_csi2_of_match_table,
> + },
> +};
> +
> +module_platform_driver(phy_qcom_mipi_csi2_driver);
> +
> +MODULE_DESCRIPTION("Qualcomm MIPI CSI2 PHY driver");
> +MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linaro.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
> new file mode 100644
> index 0000000000000..179f535121aad
> --- /dev/null
> +++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
> @@ -0,0 +1,101 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + *
> + * Qualcomm MIPI CSI2 CPHY/DPHY driver
> + *
> + * Copyright (C) 2025 Linaro Ltd.
> + */
> +#ifndef __PHY_QCOM_MIPI_CSI2_H__
> +#define __PHY_QCOM_MIPI_CSI2_H__
> +
> +#include <linux/phy/phy.h>
> +
> +#define CSI2_MAX_DATA_LANES 4
> +
> +struct mipi_csi2phy_lane {
> + u8 pos;
> + u8 pol;
> +};
> +
> +struct mipi_csi2phy_lanes_cfg {
> + struct mipi_csi2phy_lane data[CSI2_MAX_DATA_LANES];
> + struct mipi_csi2phy_lane clk;
> +};
> +
> +struct mipi_csi2phy_stream_cfg {
> + u8 combo_mode;
> + s64 link_freq;
> + u8 num_data_lanes;
> + struct mipi_csi2phy_lanes_cfg lane_cfg;
> +};
> +
> +struct mipi_csi2phy_device;
> +
> +struct mipi_csi2phy_hw_ops {
> + void (*hw_version_read)(struct mipi_csi2phy_device *csi2phy_dev);
> + void (*reset)(struct mipi_csi2phy_device *csi2phy_dev);
> + int (*lanes_enable)(struct mipi_csi2phy_device *csi2phy_dev,
> + struct mipi_csi2phy_stream_cfg *cfg);
> + void (*lanes_disable)(struct mipi_csi2phy_device *csi2phy_dev,
> + struct mipi_csi2phy_stream_cfg *cfg);
> +};
> +
> +struct mipi_csi2phy_lane_regs {
> + const s32 reg_addr;
> + const s32 reg_data;
> + const u32 delay_us;
> + const u32 param_type;
> +};
> +
> +struct mipi_csi2phy_device_regs {
> + const struct mipi_csi2phy_lane_regs *init_seq;
> + const int lane_array_size;
> + const u32 common_regs_offset;
> + enum {
> + GEN1 = 0,
> + GEN1_660,
> + GEN1_670,
> + GEN2,
> + } generation;
> +};
> +
> +struct mipi_csi2phy_soc_cfg {
> + const struct mipi_csi2phy_hw_ops *ops;
> + const struct mipi_csi2phy_device_regs reg_info;
> +
> + const char ** const supply_names;
> + const unsigned int num_supplies;
> +
> + const char ** const clk_names;
> + const unsigned int num_clk;
> +
> + const char * const opp_clk;
> + const char * const timer_clk;
> +
> + const char ** const genpd_names;
> + const unsigned int num_genpd_names;
> +};
> +
> +struct mipi_csi2phy_device {
> + struct device *dev;
> +
> + struct phy *phy;
> + void __iomem *base;
> +
> + struct clk_bulk_data *clks;
> + struct clk *timer_clk;
> + u32 timer_clk_rate;
> +
> + struct regulator_bulk_data *supplies;
> + struct device **pds;
> + unsigned int num_pds;
> +
> + const struct mipi_csi2phy_soc_cfg *soc_cfg;
> + struct mipi_csi2phy_stream_cfg stream_cfg;
> +
> + u32 hw_version;
> +};
> +
> +extern const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_4nm_x1e;
> +
> +#endif /* __PHY_QCOM_MIPI_CSI2_H__ */
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH] dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: Add Eliza QMP PHY
From: Abel Vesa @ 2026-03-18 9:54 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Abel Vesa
Document the compatible for the USB QMP PHY found on the Qualcomm Eliza
SoC.
It is fully compatible with the one found on Qualcomm SM8650, so add it
with the SM8650 as fallback.
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
.../devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
index 3d537b7f9985..4eff92343ce4 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
@@ -16,6 +16,10 @@ description:
properties:
compatible:
oneOf:
+ - items:
+ - enum:
+ - qcom,eliza-qmp-usb3-dp-phy
+ - const: qcom,sm8650-qmp-usb3-dp-phy
- items:
- enum:
- qcom,kaanapali-qmp-usb3-dp-phy
---
base-commit: 8e5a478b6d6a5bb0a3d52147862b15e4d826af19
change-id: 20260318-eliza-bindings-qmp-phy-c53be4b0b131
Best regards,
--
Abel Vesa <abel.vesa@oss.qualcomm.com>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
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