FAILED: patch "[PATCH] phy: cadence: cdns-dphy: Fix PLL lock and O_CMN_READY polling" failed to apply to 6.17-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.17-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.17.y
git checkout FETCH_HEAD
git cherry-pick -x 284fb19a3ffb1083c3ad9c00d29749d09dddb99c
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025101612-arguable-crushed-0b89@gregkh' --subject-prefix 'PATCH 6.17.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 284fb19a3ffb1083c3ad9c00d29749d09dddb99c Mon Sep 17 00:00:00 2001
From: Devarsh Thakkar <[email protected]>
Date: Fri, 4 Jul 2025 18:29:14 +0530
Subject: [PATCH] phy: cadence: cdns-dphy: Fix PLL lock and O_CMN_READY polling
PLL lockup and O_CMN_READY assertion can only happen after common state machine gets enabled by programming DPHY_CMN_SSM register, but driver was polling them before the common state machine was enabled which is incorrect. This is as per the DPHY initialization sequence as mentioned in J721E TRM [1] at section "12.7.2.4.1.2.1 Start-up Sequence Timing Diagram". It shows O_CMN_READY polling at the end after common configuration pin setup where the common configuration pin setup step enables state machine as referenced in "Table 12-1533. Common Configuration-Related Setup mentions state machine"
To fix this :
- Add new function callbacks for polling on PLL lock and O_CMN_READY assertion.
- As state machine and clocks get enabled in power_on callback only, move the clock related programming part from configure callback to power_on
callback and poll for the PLL lockup and O_CMN_READY assertion after state machine gets enabled.
- The configure callback only saves the PLL configuration received from the client driver which will be applied later on in power_on callback.
- Add checks to ensure configure is called before power_on and state machine is in disabled state before power_on callback is called.
- Disable state machine in power_off so that client driver can re-configure the PLL by following up a power_off, configure, power_on sequence.
[1]: https://www.ti.com/lit/zip/spruil1
drivers/phy/cadence/cdns-dphy.c +92 -32
@@ -92,6 +92,8 @@ struct cdns_dphy_ops {void (*set_pll_cfg)(struct cdns_dphy *dphy,const struct cdns_dphy_cfg *cfg);unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); +int (*wait_for_pll_lock)(struct cdns_dphy *dphy); +int (*wait_for_cmn_ready)(struct cdns_dphy *dphy); };struct cdns_dphy {
@@ -101,6 +103,8 @@ struct cdns_dphy {struct clk *pll_ref_clk;const struct cdns_dphy_ops *ops;struct phy *phy; +bool is_configured; +bool is_powered; };/* Order of bands is important since the index is the band number. */
@@ -186,6 +190,16 @@ static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy)return dphy->ops->get_wakeup_time_ns (dphy); } +static int cdns_dphy_wait_for_pll_lock (struct cdns_dphy *dphy) +{ +return dphy->ops->wait_for_pll_lock ? dphy->ops->wait_for_pll_lock (dphy) :0 ; +} + +static int cdns_dphy_wait_for_cmn_ready (struct cdns_dphy *dphy) +{ +return dphy->ops->wait_for_cmn_ready ? dphy->ops->wait_for_cmn_ready (dphy) :0 ; +} +static unsigned long cdns_dphy_ref_get_wakeup_time_ns (struct cdns_dphy *dphy) {/* Default wakeup time is 800 ns (in a simulated environment). */
@@ -227,7 +241,6 @@ static unsigned long cdns_dphy_j721e_get_wakeup_time_ns(struct cdns_dphy *dphy)static void cdns_dphy_j721e_set_pll_cfg (struct cdns_dphy *dphy,const struct cdns_dphy_cfg *cfg) { -u32 status;/* * set the PWM and PLL Byteclk divider settings to recommended values
@@ -244,13 +257,6 @@ static void cdns_dphy_j721e_set_pll_cfg(struct cdns_dphy *dphy,writel (DPHY_TX_J721E_WIZ_LANE_RSTB , dphy->regs +DPHY_TX_J721E_WIZ_RST_CTRL ); - -readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_PLL_CTRL , status, - (status &DPHY_TX_WIZ_PLL_LOCK ),0 ,POLL_TIMEOUT_US ); - -readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_STATUS , status, - (status &DPHY_TX_WIZ_O_CMN_READY ),0 , -POLL_TIMEOUT_US ); }static void cdns_dphy_j721e_set_psm_div (struct cdns_dphy *dphy,u8 div)
@@ -258,6 +264,23 @@ static void cdns_dphy_j721e_set_psm_div(struct cdns_dphy *dphy, u8 div)writel (div, dphy->regs +DPHY_TX_J721E_WIZ_PSM_FREQ ); } +static int cdns_dphy_j721e_wait_for_pll_lock (struct cdns_dphy *dphy) +{ +u32 status; + +return readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_PLL_CTRL , status, + status &DPHY_TX_WIZ_PLL_LOCK ,0 ,POLL_TIMEOUT_US ); +} + +static int cdns_dphy_j721e_wait_for_cmn_ready (struct cdns_dphy *dphy) +{ +u32 status; + +return readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_STATUS , status, + status &DPHY_TX_WIZ_O_CMN_READY ,0 , +POLL_TIMEOUT_US ); +} +/* * This is the reference implementation of DPHY hooks. Specific integration of * this IP may have to re-implement some of them depending on how they decided
@@ -273,6 +296,8 @@ static const struct cdns_dphy_ops j721e_dphy_ops = { .get_wakeup_time_ns = cdns_dphy_j721e_get_wakeup_time_ns, .set_pll_cfg = cdns_dphy_j721e_set_pll_cfg, .set_psm_div = cdns_dphy_j721e_set_psm_div, + .wait_for_pll_lock = cdns_dphy_j721e_wait_for_pll_lock, + .wait_for_cmn_ready = cdns_dphy_j721e_wait_for_cmn_ready, }; static int cdns_dphy_config_from_opts(struct phy *phy,
@@ -328,21 +353,36 @@ static int cdns_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,static int cdns_dphy_configure (struct phy *phy,union phy_configure_opts *opts) {struct cdns_dphy *dphy =phy_get_drvdata (phy); -struct cdns_dphy_cfg cfg = {0 }; -int ret, band_ctrl; -unsigned int reg; +int ret; - ret =cdns_dphy_config_from_opts (phy, &opts->mipi_dphy, &cfg); -if (ret) -return ret; + ret =cdns_dphy_config_from_opts (phy, &opts->mipi_dphy, &dphy->cfg); +if (!ret) + dphy->is_configured = true; + +return ret; +} + +static int cdns_dphy_power_on (struct phy *phy) +{ +struct cdns_dphy *dphy =phy_get_drvdata (phy); +int ret; +u32 reg; + +if (!dphy->is_configured || dphy->is_powered) +return -EINVAL ; + +clk_prepare_enable (dphy->psm_clk); +clk_prepare_enable (dphy->pll_ref_clk);/* * Configure the internal PSM clk divider so that the DPHY has a * 1MHz clk (or something close). */ ret =cdns_dphy_setup_psm (dphy); -if (ret) -return ret; +if (ret) { +dev_err (&dphy->phy->dev,"Failed to setup PSM with error %d\n" , ret); + goto err_power_on; + }/* * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes
@@ -357,40 +397,60 @@ static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts)* Configure the DPHY PLL that will be used to generate the TX byte * clk. */ -cdns_dphy_set_pll_cfg (dphy, &cfg); +cdns_dphy_set_pll_cfg (dphy, &dphy->cfg); - band_ctrl =cdns_dphy_tx_get_band_ctrl (opts->mipi_dphy.hs_clk_rate); -if (band_ctrl <0 ) -return band_ctrl; + ret =cdns_dphy_tx_get_band_ctrl (dphy->cfg.hs_clk_rate); +if (ret <0 ) { +dev_err (&dphy->phy->dev,"Failed to get band control value with error %d\n" , ret); + goto err_power_on; + } - reg =FIELD_PREP (DPHY_BAND_CFG_LEFT_BAND , band_ctrl) | -FIELD_PREP (DPHY_BAND_CFG_RIGHT_BAND , band_ctrl); + reg =FIELD_PREP (DPHY_BAND_CFG_LEFT_BAND , ret) | +FIELD_PREP (DPHY_BAND_CFG_RIGHT_BAND , ret);writel (reg, dphy->regs +DPHY_BAND_CFG ); -return 0 ; -} - -static int cdns_dphy_power_on (struct phy *phy) -{ -struct cdns_dphy *dphy =phy_get_drvdata (phy); - -clk_prepare_enable (dphy->psm_clk); -clk_prepare_enable (dphy->pll_ref_clk); -/* Start TX state machine. */ writel (DPHY_CMN_SSM_EN |DPHY_CMN_TX_MODE_EN , dphy->regs +DPHY_CMN_SSM ); + ret =cdns_dphy_wait_for_pll_lock (dphy); +if (ret) { +dev_err (&dphy->phy->dev,"Failed to lock PLL with error %d\n" , ret); + goto err_power_on; + } + + ret =cdns_dphy_wait_for_cmn_ready (dphy); +if (ret) { +dev_err (&dphy->phy->dev,"O_CMN_READY signal failed to assert with error %d\n" , + ret); + goto err_power_on; + } + + dphy->is_powered = true; +return 0 ; + +err_power_on: +clk_disable_unprepare (dphy->pll_ref_clk); +clk_disable_unprepare (dphy->psm_clk); + +return ret; }static int cdns_dphy_power_off (struct phy *phy) {struct cdns_dphy *dphy =phy_get_drvdata (phy); +u32 reg;clk_disable_unprepare (dphy->pll_ref_clk);clk_disable_unprepare (dphy->psm_clk); +/* Stop TX state machine. */ + reg =readl (dphy->regs +DPHY_CMN_SSM ); +writel (reg & ~DPHY_CMN_SSM_EN , dphy->regs +DPHY_CMN_SSM ); + + dphy->is_powered = false; +return 0 ; }
Sasha Levin
maintainerPATCH 1/2 phy: cdns-dphy: Store hs_clk_rate and return it
From: Tomi Valkeinen <[email protected]>
[ Upstream commit 689a54acb56858c85de8c7285db82b8ae6dbf683 ]
The DPHY driver does not return the actual hs_clk_rate, so the DSI driver has no idea what clock was actually achieved. Set the realized hs_clk_rate to the opts struct, so that the DSI driver gets it back.
Stable-dep-of: 284fb19a3ffb ("phy: cadence: cdns-dphy: Fix PLL lock and O_CMN_READY polling")
--- drivers/phy/cadence/cdns-dphy.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/phy/cadence/cdns-dphy.c +5 -0
@@ -79,6 +79,7 @@ struct cdns_dphy_cfg {u8 pll_ipdiv;u8 pll_opdiv;u16 pll_fbdiv; +u32 hs_clk_rate;unsigned int nlanes; };
@@ -154,6 +155,9 @@ static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, cfg->pll_ipdiv, pll_ref_hz); + cfg->hs_clk_rate =div_u64 ((u64 )pll_ref_hz * cfg->pll_fbdiv, +2 * cfg->pll_opdiv * cfg->pll_ipdiv); +return 0 ; }
@@ -297,6 +301,7 @@ static int cdns_dphy_config_from_opts(struct phy *phy,if (ret)return ret; + opts->hs_clk_rate = cfg->hs_clk_rate; opts->wakeup =cdns_dphy_get_wakeup_time_ns (dphy) /1000 ;return 0 ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/2 phy: cadence: cdns-dphy: Fix PLL lock and O_CMN_READY polling
From: Devarsh Thakkar <[email protected]>
[ Upstream commit 284fb19a3ffb1083c3ad9c00d29749d09dddb99c ]
PLL lockup and O_CMN_READY assertion can only happen after common state machine gets enabled by programming DPHY_CMN_SSM register, but driver was polling them before the common state machine was enabled which is incorrect. This is as per the DPHY initialization sequence as mentioned in J721E TRM [1] at section "12.7.2.4.1.2.1 Start-up Sequence Timing Diagram". It shows O_CMN_READY polling at the end after common configuration pin setup where the common configuration pin setup step enables state machine as referenced in "Table 12-1533. Common Configuration-Related Setup mentions state machine"
To fix this :
- Add new function callbacks for polling on PLL lock and O_CMN_READY assertion.
- As state machine and clocks get enabled in power_on callback only, move the clock related programming part from configure callback to power_on
callback and poll for the PLL lockup and O_CMN_READY assertion after state machine gets enabled.
- The configure callback only saves the PLL configuration received from the client driver which will be applied later on in power_on callback.
- Add checks to ensure configure is called before power_on and state machine is in disabled state before power_on callback is called.
- Disable state machine in power_off so that client driver can re-configure the PLL by following up a power_off, configure, power_on sequence.
[1]: https://www.ti.com/lit/zip/spruil1
--- drivers/phy/cadence/cdns-dphy.c | 124 +++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 32 deletions(-)
drivers/phy/cadence/cdns-dphy.c +92 -32
@@ -100,6 +100,8 @@ struct cdns_dphy_ops {void (*set_pll_cfg)(struct cdns_dphy *dphy,const struct cdns_dphy_cfg *cfg);unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); +int (*wait_for_pll_lock)(struct cdns_dphy *dphy); +int (*wait_for_cmn_ready)(struct cdns_dphy *dphy); };struct cdns_dphy {
@@ -109,6 +111,8 @@ struct cdns_dphy {struct clk *pll_ref_clk;const struct cdns_dphy_ops *ops;struct phy *phy; +bool is_configured; +bool is_powered; };/* Order of bands is important since the index is the band number. */
@@ -195,6 +199,16 @@ static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy)return dphy->ops->get_wakeup_time_ns (dphy); } +static int cdns_dphy_wait_for_pll_lock (struct cdns_dphy *dphy) +{ +return dphy->ops->wait_for_pll_lock ? dphy->ops->wait_for_pll_lock (dphy) :0 ; +} + +static int cdns_dphy_wait_for_cmn_ready (struct cdns_dphy *dphy) +{ +return dphy->ops->wait_for_cmn_ready ? dphy->ops->wait_for_cmn_ready (dphy) :0 ; +} +static unsigned long cdns_dphy_ref_get_wakeup_time_ns (struct cdns_dphy *dphy) {/* Default wakeup time is 800 ns (in a simulated environment). */
@@ -236,7 +250,6 @@ static unsigned long cdns_dphy_j721e_get_wakeup_time_ns(struct cdns_dphy *dphy)static void cdns_dphy_j721e_set_pll_cfg (struct cdns_dphy *dphy,const struct cdns_dphy_cfg *cfg) { -u32 status;/* * set the PWM and PLL Byteclk divider settings to recommended values
@@ -253,13 +266,6 @@ static void cdns_dphy_j721e_set_pll_cfg(struct cdns_dphy *dphy,writel (DPHY_TX_J721E_WIZ_LANE_RSTB , dphy->regs +DPHY_TX_J721E_WIZ_RST_CTRL ); - -readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_PLL_CTRL , status, - (status &DPHY_TX_WIZ_PLL_LOCK ),0 ,POLL_TIMEOUT_US ); - -readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_STATUS , status, - (status &DPHY_TX_WIZ_O_CMN_READY ),0 , -POLL_TIMEOUT_US ); }static void cdns_dphy_j721e_set_psm_div (struct cdns_dphy *dphy,u8 div)
@@ -267,6 +273,23 @@ static void cdns_dphy_j721e_set_psm_div(struct cdns_dphy *dphy, u8 div)writel (div, dphy->regs +DPHY_TX_J721E_WIZ_PSM_FREQ ); } +static int cdns_dphy_j721e_wait_for_pll_lock (struct cdns_dphy *dphy) +{ +u32 status; + +return readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_PLL_CTRL , status, + status &DPHY_TX_WIZ_PLL_LOCK ,0 ,POLL_TIMEOUT_US ); +} + +static int cdns_dphy_j721e_wait_for_cmn_ready (struct cdns_dphy *dphy) +{ +u32 status; + +return readl_poll_timeout (dphy->regs +DPHY_TX_J721E_WIZ_STATUS , status, + status &DPHY_TX_WIZ_O_CMN_READY ,0 , +POLL_TIMEOUT_US ); +} +/* * This is the reference implementation of DPHY hooks. Specific integration of * this IP may have to re-implement some of them depending on how they decided
@@ -282,6 +305,8 @@ static const struct cdns_dphy_ops j721e_dphy_ops = { .get_wakeup_time_ns = cdns_dphy_j721e_get_wakeup_time_ns, .set_pll_cfg = cdns_dphy_j721e_set_pll_cfg, .set_psm_div = cdns_dphy_j721e_set_psm_div, + .wait_for_pll_lock = cdns_dphy_j721e_wait_for_pll_lock, + .wait_for_cmn_ready = cdns_dphy_j721e_wait_for_cmn_ready, }; static int cdns_dphy_config_from_opts(struct phy *phy,
@@ -339,21 +364,36 @@ static int cdns_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,static int cdns_dphy_configure (struct phy *phy,union phy_configure_opts *opts) {struct cdns_dphy *dphy =phy_get_drvdata (phy); -struct cdns_dphy_cfg cfg = {0 }; -int ret, band_ctrl; -unsigned int reg; +int ret; - ret =cdns_dphy_config_from_opts (phy, &opts->mipi_dphy, &cfg); -if (ret) -return ret; + ret =cdns_dphy_config_from_opts (phy, &opts->mipi_dphy, &dphy->cfg); +if (!ret) + dphy->is_configured = true; + +return ret; +} + +static int cdns_dphy_power_on (struct phy *phy) +{ +struct cdns_dphy *dphy =phy_get_drvdata (phy); +int ret; +u32 reg; + +if (!dphy->is_configured || dphy->is_powered) +return -EINVAL ; + +clk_prepare_enable (dphy->psm_clk); +clk_prepare_enable (dphy->pll_ref_clk);/* * Configure the internal PSM clk divider so that the DPHY has a * 1MHz clk (or something close). */ ret =cdns_dphy_setup_psm (dphy); -if (ret) -return ret; +if (ret) { +dev_err (&dphy->phy->dev,"Failed to setup PSM with error %d\n" , ret); + goto err_power_on; + }/* * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes
@@ -368,40 +408,60 @@ static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts)* Configure the DPHY PLL that will be used to generate the TX byte * clk. */ -cdns_dphy_set_pll_cfg (dphy, &cfg); +cdns_dphy_set_pll_cfg (dphy, &dphy->cfg); - band_ctrl =cdns_dphy_tx_get_band_ctrl (opts->mipi_dphy.hs_clk_rate); -if (band_ctrl <0 ) -return band_ctrl; + ret =cdns_dphy_tx_get_band_ctrl (dphy->cfg.hs_clk_rate); +if (ret <0 ) { +dev_err (&dphy->phy->dev,"Failed to get band control value with error %d\n" , ret); + goto err_power_on; + } - reg =FIELD_PREP (DPHY_BAND_CFG_LEFT_BAND , band_ctrl) | -FIELD_PREP (DPHY_BAND_CFG_RIGHT_BAND , band_ctrl); + reg =FIELD_PREP (DPHY_BAND_CFG_LEFT_BAND , ret) | +FIELD_PREP (DPHY_BAND_CFG_RIGHT_BAND , ret);writel (reg, dphy->regs +DPHY_BAND_CFG ); -return 0 ; -} - -static int cdns_dphy_power_on (struct phy *phy) -{ -struct cdns_dphy *dphy =phy_get_drvdata (phy); - -clk_prepare_enable (dphy->psm_clk); -clk_prepare_enable (dphy->pll_ref_clk); -/* Start TX state machine. */ writel (DPHY_CMN_SSM_EN |DPHY_CMN_TX_MODE_EN , dphy->regs +DPHY_CMN_SSM ); + ret =cdns_dphy_wait_for_pll_lock (dphy); +if (ret) { +dev_err (&dphy->phy->dev,"Failed to lock PLL with error %d\n" , ret); + goto err_power_on; + } + + ret =cdns_dphy_wait_for_cmn_ready (dphy); +if (ret) { +dev_err (&dphy->phy->dev,"O_CMN_READY signal failed to assert with error %d\n" , + ret); + goto err_power_on; + } + + dphy->is_powered = true; +return 0 ; + +err_power_on: +clk_disable_unprepare (dphy->pll_ref_clk); +clk_disable_unprepare (dphy->psm_clk); + +return ret; }static int cdns_dphy_power_off (struct phy *phy) {struct cdns_dphy *dphy =phy_get_drvdata (phy); +u32 reg;clk_disable_unprepare (dphy->pll_ref_clk);clk_disable_unprepare (dphy->psm_clk); +/* Stop TX state machine. */ + reg =readl (dphy->regs +DPHY_CMN_SSM ); +writel (reg & ~DPHY_CMN_SSM_EN , dphy->regs +DPHY_CMN_SSM ); + + dphy->is_powered = false; +return 0 ; }
Signature · 1 line
2.51.0