Skip to content

Commit cb55f39

Browse files
krzklumag
authored andcommitted
drm/msm/dsi/phy: Fix reading zero as PLL rates when unprepared
Hardware Programming Guide for DSI PHY says that PLL_SHUTDOWNB and DIGTOP_PWRDN_B have to be asserted for any PLL register access. Whenever dsi_pll_7nm_vco_recalc_rate() or dsi_pll_7nm_vco_set_rate() were called on unprepared PLL, driver read values of zero leading to all sort of further troubles, like failing to set pixel and byte clock rates. Asserting the PLL shutdown bit is done by dsi_pll_enable_pll_bias() (and corresponding dsi_pll_disable_pll_bias()) which are called through the code, including from PLL .prepare() and .unprepare() callbacks. The .set_rate() and .recalc_rate() can be called almost anytime from external users including times when PLL is or is not prepared, thus driver should not interfere with the prepare status. Implement simple reference counting for the PLL bias, so set_rate/recalc_rate will not change the status of prepared PLL. Issue of reading 0 in .recalc_rate() did not show up on existing devices, but only after re-ordering the code for SM8750. Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Patchwork: https://patchwork.freedesktop.org/patch/673416/ Link: https://lore.kernel.org/r/20250908094950.72877-2-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
1 parent 6341516 commit cb55f39

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

drivers/gpu/drm/msm/dsi/phy/dsi_phy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ struct msm_dsi_phy {
109109
struct msm_dsi_dphy_timing timing;
110110
const struct msm_dsi_phy_cfg *cfg;
111111
void *tuning_cfg;
112+
void *pll_data;
112113

113114
enum msm_dsi_phy_usecase usecase;
114115
bool regulator_ldo_mode;

drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ struct dsi_pll_7nm {
9090
/* protects REG_DSI_7nm_PHY_CMN_CLK_CFG1 register */
9191
spinlock_t pclk_mux_lock;
9292

93+
/*
94+
* protects REG_DSI_7nm_PHY_CMN_CTRL_0 register and pll_enable_cnt
95+
* member
96+
*/
97+
spinlock_t pll_enable_lock;
98+
int pll_enable_cnt;
99+
93100
struct pll_7nm_cached_state cached_state;
94101

95102
struct dsi_pll_7nm *slave;
@@ -103,6 +110,9 @@ struct dsi_pll_7nm {
103110
*/
104111
static struct dsi_pll_7nm *pll_7nm_list[DSI_MAX];
105112

113+
static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll);
114+
static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll);
115+
106116
static void dsi_pll_setup_config(struct dsi_pll_config *config)
107117
{
108118
config->ssc_freq = 31500;
@@ -340,6 +350,7 @@ static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
340350
struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
341351
struct dsi_pll_config config;
342352

353+
dsi_pll_enable_pll_bias(pll_7nm);
343354
DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_7nm->phy->id, rate,
344355
parent_rate);
345356

@@ -357,6 +368,7 @@ static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
357368

358369
dsi_pll_ssc_commit(pll_7nm, &config);
359370

371+
dsi_pll_disable_pll_bias(pll_7nm);
360372
/* flush, ensure all register writes are done*/
361373
wmb();
362374

@@ -385,24 +397,47 @@ static int dsi_pll_7nm_lock_status(struct dsi_pll_7nm *pll)
385397

386398
static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll)
387399
{
400+
unsigned long flags;
388401
u32 data;
389402

403+
spin_lock_irqsave(&pll->pll_enable_lock, flags);
404+
--pll->pll_enable_cnt;
405+
if (pll->pll_enable_cnt < 0) {
406+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
407+
DRM_DEV_ERROR_RATELIMITED(&pll->phy->pdev->dev,
408+
"bug: imbalance in disabling PLL bias\n");
409+
return;
410+
} else if (pll->pll_enable_cnt > 0) {
411+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
412+
return;
413+
} /* else: == 0 */
414+
390415
data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
391416
data &= ~DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
392417
writel(0, pll->phy->pll_base + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES);
393418
writel(data, pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
419+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
394420
ndelay(250);
395421
}
396422

397423
static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll)
398424
{
425+
unsigned long flags;
399426
u32 data;
400427

428+
spin_lock_irqsave(&pll->pll_enable_lock, flags);
429+
if (pll->pll_enable_cnt++) {
430+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
431+
WARN_ON(pll->pll_enable_cnt == INT_MAX);
432+
return;
433+
}
434+
401435
data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
402436
data |= DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
403437
writel(data, pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
404438

405439
writel(0xc0, pll->phy->pll_base + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES);
440+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
406441
ndelay(250);
407442
}
408443

@@ -543,6 +578,7 @@ static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw,
543578
u32 dec;
544579
u64 pll_freq, tmp64;
545580

581+
dsi_pll_enable_pll_bias(pll_7nm);
546582
dec = readl(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1);
547583
dec &= 0xff;
548584

@@ -567,6 +603,8 @@ static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw,
567603
DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
568604
pll_7nm->phy->id, (unsigned long)vco_rate, dec, frac);
569605

606+
dsi_pll_disable_pll_bias(pll_7nm);
607+
570608
return (unsigned long)vco_rate;
571609
}
572610

@@ -600,6 +638,7 @@ static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy)
600638
void __iomem *phy_base = pll_7nm->phy->base;
601639
u32 cmn_clk_cfg0, cmn_clk_cfg1;
602640

641+
dsi_pll_enable_pll_bias(pll_7nm);
603642
cached->pll_out_div = readl(pll_7nm->phy->pll_base +
604643
REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE);
605644
cached->pll_out_div &= 0x3;
@@ -611,6 +650,7 @@ static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy)
611650
cmn_clk_cfg1 = readl(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
612651
cached->pll_mux = FIELD_GET(DSI_7nm_PHY_CMN_CLK_CFG1_DSICLK_SEL__MASK, cmn_clk_cfg1);
613652

653+
dsi_pll_disable_pll_bias(pll_7nm);
614654
DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
615655
pll_7nm->phy->id, cached->pll_out_div, cached->bit_clk_div,
616656
cached->pix_clk_div, cached->pll_mux);
@@ -833,8 +873,10 @@ static int dsi_pll_7nm_init(struct msm_dsi_phy *phy)
833873

834874
spin_lock_init(&pll_7nm->postdiv_lock);
835875
spin_lock_init(&pll_7nm->pclk_mux_lock);
876+
spin_lock_init(&pll_7nm->pll_enable_lock);
836877

837878
pll_7nm->phy = phy;
879+
phy->pll_data = pll_7nm;
838880

839881
ret = pll_7nm_register(pll_7nm, phy->provided_clocks->hws);
840882
if (ret) {
@@ -923,8 +965,10 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
923965
u32 const delay_us = 5;
924966
u32 const timeout_us = 1000;
925967
struct msm_dsi_dphy_timing *timing = &phy->timing;
968+
struct dsi_pll_7nm *pll = phy->pll_data;
926969
void __iomem *base = phy->base;
927970
bool less_than_1500_mhz;
971+
unsigned long flags;
928972
u32 vreg_ctrl_0, vreg_ctrl_1, lane_ctrl0;
929973
u32 glbl_pemph_ctrl_0;
930974
u32 glbl_str_swi_cal_sel_ctrl, glbl_hstx_str_ctrl_0;
@@ -1046,10 +1090,13 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
10461090
glbl_rescode_bot_ctrl = 0x3c;
10471091
}
10481092

1093+
spin_lock_irqsave(&pll->pll_enable_lock, flags);
1094+
pll->pll_enable_cnt = 1;
10491095
/* de-assert digital and pll power down */
10501096
data = DSI_7nm_PHY_CMN_CTRL_0_DIGTOP_PWRDN_B |
10511097
DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
10521098
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
1099+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
10531100

10541101
/* Assert PLL core reset */
10551102
writel(0x00, base + REG_DSI_7nm_PHY_CMN_PLL_CNTRL);
@@ -1162,7 +1209,9 @@ static bool dsi_7nm_set_continuous_clock(struct msm_dsi_phy *phy, bool enable)
11621209

11631210
static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
11641211
{
1212+
struct dsi_pll_7nm *pll = phy->pll_data;
11651213
void __iomem *base = phy->base;
1214+
unsigned long flags;
11661215
u32 data;
11671216

11681217
DBG("");
@@ -1189,8 +1238,12 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
11891238
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
11901239
writel(0, base + REG_DSI_7nm_PHY_CMN_LANE_CTRL0);
11911240

1241+
spin_lock_irqsave(&pll->pll_enable_lock, flags);
1242+
pll->pll_enable_cnt = 0;
11921243
/* Turn off all PHY blocks */
11931244
writel(0x00, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
1245+
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
1246+
11941247
/* make sure phy is turned off */
11951248
wmb();
11961249

0 commit comments

Comments
 (0)