From: Gustavo Sousa <gustavo.sousa@intel.com>
To: "Kandpal, Suraj" <suraj.kandpal@intel.com>,
"intel-gfx@lists.freedesktop.org"
<intel-gfx@lists.freedesktop.org>,
"intel-xe@lists.freedesktop.org" <intel-xe@lists.freedesktop.org>
Cc: "Nautiyal, Ankit K" <ankit.k.nautiyal@intel.com>,
"Kahola, Mika" <mika.kahola@intel.com>
Subject: RE: [PATCH 1/3] drm/i915/cx0: Split PLL enabling/disabling in two parts
Date: Mon, 5 Jan 2026 11:13:42 -0300 [thread overview]
Message-ID: <176762242212.9480.15194458566987361794@intel.com> (raw)
In-Reply-To: <DM3PPF208195D8D3196DF977339A8FB7CB2E3BDA@DM3PPF208195D8D.namprd11.prod.outlook.com>
Quoting Kandpal, Suraj (2025-12-31 02:07:35-03:00)
>> Subject: Re: [PATCH 1/3] drm/i915/cx0: Split PLL enabling/disabling in two
>> parts
>>
>> Quoting Suraj Kandpal (2025-12-30 05:31:40-03:00)
>> >From: Mika Kahola <mika.kahola@intel.com>
>> >
>> >Split PLL enabling/disabling in two parts - one for pll setting pll
>> >dividers and second one to enable/disable pll clock. PLL clock
>> >enabling/disbling happens via encoder->enable_clock/disable_clock
>> >function hook. The reason for doing this is that we need to make sure
>> >the clock enablement happens after PPS ON step to be inline with the
>> >sequences which we end up violating otherwise. As a result of this
>> >violation we end up in a hanged state if machine stays idle for more
>> >that 15 mins.
>>
>> So, it appears this started happening when we Cx0 code was integrated into
>> the DPLL framework and then the driver started enabling the PHY PLL/clock
>> too early, right?
>>
>> I am lacking some context/background here due to my unfamiliarity with pre-
>> MTL platforms, but why I exactly do we program the PLLs before the modeset
>> sequence? Is it related to the shared nature of PLLs for platforms pre-
>> C10/pre-C20? If so, do we really need to do the same for
>> C10/C20 PHYs, since we have dedicated PLLs for them?
>>
>> (Sorry for asking here and a bit too late. Probably the better place to ask this
>> was in series that integrated Cx0 into the DPLL framework.)
>
>
>Right it used to be actually because of the shared nature of PLL's. With c10 c20 we moved
>to a different framework where we called the the sequence together using hooks like enable_clock
>and disable_clock since there was not a lot of time of time to refactor the dpll_shared_framework to
>a framework with supported individual ones.
>Now that we had time we shifted cx0 back to the previous framework but missed defer the clock enablement
Then, if we move forward with this, perhaps this patch deserves a
"Fixes:" trailer.
>To later during enable clock time so that we honor the sequence, why we had to do this is even though its not shared PLL anymore is
>To make sure this framework is backward compatible too.
I see.
If the requirement for programming PLL parameters early was only because
of shared PLLs and we do not have that same requirements for C10/C20, I
would argue that doing the whole programming at once and only during the
"enable clock" phase of the encoder would make the driver more compliant
with the Bspec.
I also noticed that, for the older displays, the "enable clock" thing is
the part that selects the PLL (which is already enabled) as the port's
"clock source". With C10/C20 we are actually deferring the PLL enabling
to the "enable clock" phase of the port while, I believe, the
expectation of intel_dpll_funcs::enable() is that the PLL would be
enabled when the function returned, which would not be exactly true for
C10/C20 after this patch.
What if, in intel_dpll_mgr, we made the distinction between enabling the
PLL early and enabling it at "intel_ddi_enable_clock()" time?
--
Gustavo Sousa
>Also we had to move cx0 pll framework back to dpll framework because the previous can work well as long as the ports are static hence aren’t
>As future proof , we plan to move LT PHY back here too once this ages well.
>
>>
>> >
>> >PLL state verification happens now earlier than the clock is enabled
>> >which causes a drm warn to be thrown. Silence this warning by allowing
>> >this check for only earlier platforms than MeteorLake.
>> >
>> >Bspec: 49190
>>
>> This Bspec page is not invalid for platforms using C10/C20 PHYs.
>>
>> We probably want to use these instead:
>>
>> Bspec: 65448, 68849
>>
>
>Sure will replace them.
>
>Regards,
>Suraj Kandpal
>
>> --
>> Gustavo Sousa
>>
>> >Signed-off-by: Mika Kahola <mika.kahola@intel.com>
>> >Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
>> >---
>> > drivers/gpu/drm/i915/display/intel_cx0_phy.c | 87 ++++++++++++-------
>> >drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 12 +--
>> > 2 files changed, 64 insertions(+), 35 deletions(-)
>> >
>> >diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
>> >b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
>> >index 7288065d2461..f3baba264e88 100644
>> >--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
>> >+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
>> >@@ -3225,11 +3225,8 @@ static void intel_cx0pll_enable(struct
>> >intel_encoder *encoder, {
>> > int port_clock = pll_state->use_c10 ? pll_state->c10.clock : pll_state-
>> >c20.clock;
>> > struct intel_display *display = to_intel_display(encoder);
>> >- enum phy phy = intel_encoder_to_phy(encoder);
>> > struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
>> > bool lane_reversal = dig_port->lane_reversal;
>> >- u8 maxpclk_lane = lane_reversal ? INTEL_CX0_LANE1 :
>> >- INTEL_CX0_LANE0;
>> > struct ref_tracker *wakeref =
>> >intel_cx0_phy_transaction_begin(encoder);
>> >
>> > /*
>> >@@ -3284,27 +3281,6 @@ static void intel_cx0pll_enable(struct
>> intel_encoder *encoder,
>> > */
>> > intel_de_write(display, DDI_CLK_VALFREQ(encoder->port),
>> >port_clock);
>> >
>> >- /*
>> >- * 9. Set PORT_CLOCK_CTL register PCLK PLL Request
>> >- * LN<Lane for maxPCLK> to "1" to enable PLL.
>> >- */
>> >- intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder-
>> >port),
>> >- intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES),
>> >- intel_cx0_get_pclk_pll_request(maxpclk_lane));
>> >-
>> >- /* 10. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK>
>> == "1". */
>> >- if (intel_de_wait_us(display, XELPDP_PORT_CLOCK_CTL(display,
>> encoder->port),
>> >- intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES),
>> >- intel_cx0_get_pclk_pll_ack(maxpclk_lane),
>> >- XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, NULL))
>> >- drm_warn(display->drm, "Port %c PLL not locked\n",
>> >- phy_name(phy));
>> >-
>> >- /*
>> >- * 11. Follow the Display Voltage Frequency Switching Sequence After
>> >- * Frequency Change. We handle this step in bxt_set_cdclk().
>> >- */
>> >-
>> > /*
>> > * 12. Toggle powerdown if HDMI is enabled on C10 PHY.
>> > *
>> >@@ -3403,6 +3379,42 @@ static int intel_mtl_tbt_clock_select(struct
>> intel_display *display,
>> > }
>> > }
>> >
>> >+static void intel_cx0pll_enable_clock(struct intel_encoder *encoder) {
>> >+ struct intel_display *display = to_intel_display(encoder);
>> >+ enum phy phy = intel_encoder_to_phy(encoder);
>> >+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
>> >+ bool lane_reversal = dig_port->lane_reversal;
>> >+ INTEL_CX0_LANE0;
>> >+ u8 maxpclk_lane = lane_reversal ? INTEL_CX0_LANE1 :
>> >+ INTEL_CX0_LANE0;
>> >+
>> >+ struct ref_tracker *wakeref =
>> >+ intel_cx0_phy_transaction_begin(encoder);
>> >+
>> >+ /*
>> >+ * 9. Set PORT_CLOCK_CTL register PCLK PLL Request
>> >+ * LN<Lane for maxPCLK> to "1" to enable PLL.
>> >+ */
>> >+ intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder-
>> >port),
>> >+ intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES),
>> >+ intel_cx0_get_pclk_pll_request(maxpclk_lane));
>> >+
>> >+ /* 10. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK>
>> == "1". */
>> >+ if (intel_de_wait_us(display, XELPDP_PORT_CLOCK_CTL(display,
>> encoder->port),
>> >+ intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES),
>> >+ intel_cx0_get_pclk_pll_ack(maxpclk_lane),
>> >+ XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, NULL))
>> >+ drm_warn(display->drm, "Port %c PLL not locked\n",
>> >+ phy_name(phy));
>> >+
>> >+ /*
>> >+ * 11. Follow the Display Voltage Frequency Switching Sequence After
>> >+ * Frequency Change. We handle this step in bxt_set_cdclk().
>> >+ */
>> >+
>> >+ intel_cx0_phy_transaction_end(encoder, wakeref); }
>> >+
>> > void intel_mtl_tbt_pll_enable_clock(struct intel_encoder *encoder, int
>> >port_clock) {
>> > struct intel_display *display = to_intel_display(encoder); @@
>> >-3472,6 +3484,8 @@ void intel_mtl_pll_enable_clock(struct intel_encoder
>> >*encoder,
>> >
>> > if (intel_tc_port_in_tbt_alt_mode(dig_port))
>> > intel_mtl_tbt_pll_enable_clock(encoder,
>> > crtc_state->port_clock);
>> >+ else
>> >+ intel_cx0pll_enable_clock(encoder);
>> > }
>> >
>> > /*
>> >@@ -3567,12 +3581,6 @@ static void intel_cx0pll_disable(struct
>> intel_encoder *encoder)
>> > * Frequency Change. We handle this step in bxt_set_cdclk().
>> > */
>> >
>> >- /* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */
>> >- intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder-
>> >port),
>> >- XELPDP_DDI_CLOCK_SELECT_MASK(display), 0);
>> >- intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder-
>> >port),
>> >- XELPDP_FORWARD_CLOCK_UNGATE, 0);
>> >-
>> > intel_cx0_phy_transaction_end(encoder, wakeref); }
>> >
>> >@@ -3586,6 +3594,20 @@ static bool intel_cx0_pll_is_enabled(struct
>> intel_encoder *encoder)
>> > intel_cx0_get_pclk_pll_request(lane);
>> > }
>> >
>> >+static void intel_cx0pll_disable_clock(struct intel_encoder *encoder)
>> >+{
>> >+ struct intel_display *display = to_intel_display(encoder);
>> >+ struct ref_tracker *wakeref =
>> >+intel_cx0_phy_transaction_begin(encoder);
>> >+
>> >+ /* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */
>> >+ intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder-
>> >port),
>> >+ XELPDP_DDI_CLOCK_SELECT_MASK(display), 0);
>> >+ intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder-
>> >port),
>> >+ XELPDP_FORWARD_CLOCK_UNGATE, 0);
>> >+
>> >+ intel_cx0_phy_transaction_end(encoder, wakeref); }
>> >+
>> > void intel_mtl_tbt_pll_disable_clock(struct intel_encoder *encoder) {
>> > struct intel_display *display = to_intel_display(encoder); @@
>> >-3635,6 +3657,9 @@ void intel_mtl_pll_disable_clock(struct
>> >intel_encoder *encoder)
>> >
>> > if (intel_tc_port_in_tbt_alt_mode(dig_port))
>> > intel_mtl_tbt_pll_disable_clock(encoder);
>> >+ else
>> >+ intel_cx0pll_disable_clock(encoder);
>> >+
>> > }
>> >
>> > enum icl_port_dpll_id
>> >@@ -3783,6 +3808,8 @@ void intel_cx0_pll_power_save_wa(struct
>> intel_display *display)
>> > encoder->base.base.id,
>> >encoder->base.name);
>> >
>> > intel_cx0pll_enable(encoder, &pll_state);
>> >+ intel_cx0pll_enable_clock(encoder);
>> > intel_cx0pll_disable(encoder);
>> >+ intel_cx0pll_disable_clock(encoder);
>> > }
>> > }
>> >diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
>> >b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
>> >index 9aa84a430f09..59395076103c 100644
>> >--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
>> >+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
>> >@@ -186,11 +186,13 @@ void assert_dpll(struct intel_display *display,
>> > "asserting DPLL %s with no DPLL\n", str_on_off(state)))
>> > return;
>> >
>> >- cur_state = intel_dpll_get_hw_state(display, pll, &hw_state);
>> >- INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
>> >- "%s assertion failure (expected %s, current %s)\n",
>> >- pll->info->name, str_on_off(state),
>> >- str_on_off(cur_state));
>> >+ if (DISPLAY_VER(display) < 14) {
>> >+ cur_state = intel_dpll_get_hw_state(display, pll, &hw_state);
>> >+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
>> >+ "%s assertion failure (expected %s, current %s)\n",
>> >+ pll->info->name, str_on_off(state),
>> >+ str_on_off(cur_state));
>> >+ }
>> > }
>> >
>> > static enum tc_port icl_pll_id_to_tc_port(enum intel_dpll_id id)
>> >--
>> >2.34.1
>> >
next prev parent reply other threads:[~2026-01-05 14:13 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-30 8:31 [PATCH 0/3] Fix Cx0 Suspend Resume issue Suraj Kandpal
2025-12-30 8:31 ` [PATCH 1/3] drm/i915/cx0: Split PLL enabling/disabling in two parts Suraj Kandpal
2025-12-30 15:20 ` Gustavo Sousa
2025-12-31 5:07 ` Kandpal, Suraj
2026-01-05 14:13 ` Gustavo Sousa [this message]
2026-01-06 6:19 ` Kandpal, Suraj
2026-01-08 8:51 ` Kahola, Mika
2025-12-30 21:23 ` kernel test robot
2026-01-07 15:22 ` Michał Grzelak
2025-12-30 8:31 ` [PATCH 2/3] drm/i915/cx0: Move step 12 to enable clock hook Suraj Kandpal
2025-12-30 15:22 ` Gustavo Sousa
2025-12-31 5:10 ` Kandpal, Suraj
2026-01-05 14:37 ` Gustavo Sousa
2026-01-06 6:18 ` Kandpal, Suraj
2025-12-30 8:31 ` [PATCH 3/3] drm/i915/cx0: Clear response ready & error bit Suraj Kandpal
2025-12-30 15:29 ` Jani Nikula
2025-12-30 17:36 ` Gustavo Sousa
2025-12-31 4:59 ` Kandpal, Suraj
2026-01-05 15:14 ` Gustavo Sousa
2026-01-06 6:21 ` Kandpal, Suraj
2025-12-30 8:42 ` ✗ Fi.CI.BUILD: failure for Fix Cx0 Suspend Resume issue Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=176762242212.9480.15194458566987361794@intel.com \
--to=gustavo.sousa@intel.com \
--cc=ankit.k.nautiyal@intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--cc=mika.kahola@intel.com \
--cc=suraj.kandpal@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox