mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kuogee Hsieh <quic_khsieh@quicinc.com>
To: Stephen Boyd <swboyd@chromium.org>, <agross@kernel.org>,
	<airlied@linux.ie>, <bjorn.andersson@linaro.org>,
	<daniel@ffwll.ch>, <dmitry.baryshkov@linaro.org>,
	<dri-devel@lists.freedesktop.org>, <robdclark@gmail.com>,
	<sean@poorly.run>, <vkoul@kernel.org>
Cc: <quic_abhinavk@quicinc.com>, <aravindh@codeaurora.org>,
	<quic_sbillaka@quicinc.com>, <freedreno@lists.freedesktop.org>,
	<linux-arm-msm@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v11 1/4] drm/msm/dp: do not initialize phy until plugin interrupt received
Date: Thu, 13 Jan 2022 09:51:42 -0800	[thread overview]
Message-ID: <338ae657-e8ed-e620-0aa7-4ad05df18ad1@quicinc.com> (raw)
In-Reply-To: <CAE-0n5134H0puMicozjdfTY+zXVUZyrebjv7Hto3EWcQAELO4A@mail.gmail.com>


On 1/12/2022 8:13 PM, Stephen Boyd wrote:
> Quoting Kuogee Hsieh (2022-01-12 14:17:54)
>> On 1/12/2022 12:00 PM, Stephen Boyd wrote:
>>> Quoting Kuogee Hsieh (2022-01-11 10:43:23)
>>>> Current DP drivers have regulators, clocks, irq and phy are grouped
>>>> together within a function and executed not in a symmetric manner.
>>>> This increase difficulty of code maintenance and limited code scalability.
>>>> This patch divides the driver life cycle of operation into four states,
>>>> resume (including booting up), dongle plugin, dongle unplugged and suspend.
>>>> Regulators, core clocks and irq are grouped together and enabled at resume
>>>> (or booting up) so that the DP controller is armed and ready to receive HPD
>>>> plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
>>>> into DUT (device under test). Once HPD plugin interrupt is received, DP
>>>> controller will initialize phy so that dpcd read/write will function and
>>>> following link training can be proceeded successfully. DP phy will be
>>>> disabled after main link is teared down at end of unplugged HPD interrupt
>>>> handle triggered by dongle unplugged out of DUT. Finally regulators, code
>>>> clocks and irq are disabled at corresponding suspension.
>> 0) Please note that  dongles are behavior differently.
>>
>> 1) Apple dongle will generate plug-in interrupt only if no hdmi monitor
>> atatched to dongle. it will generate irq-hpd interrupt once hdmi monitor
>> connect to dongle later.
>>
>> 2) Apple dongle will generate plugged-in interrupt followed by irq-hpd
>> interrupt if dongle has hdmi monitor attached when connects to DUT.
>>
>> 3) other dongle will not generate plug-in interrupt unless dongle has
>> hdmi monitor attached when connects to DUT. It only generate plug-in
>> interrupt only and no irq-hpd interrupt  generated on this case.
> Ok. The test scenarios can be reworded in terms of plugin irq and
> irq-hpd if that makes it easier.
>
>> 4) Note: phy_initialized only associated with plugged-in interrupt
>>
>> 5) irq-hpd interrupt must happen after plugged-in interrupt and before
>> unplugged interrupt
> More precisely it's that plugged-in interrupt must be handled before
> irq-hpd but plugged-in and irq-hpd can both be pending at the device
> concurrently unless they're masked and unmasked in some particular
> order. I thought the driver ensures that only irq-hpd is unmasked once
> the plugged in irq is handled. Can you confirm? Similarly, unplugged irq
> is unmasked after plugged in irq is handled, but irq-hpd and unplugged
> can both be pending if the irq handler is delayed?

we went through this before,

1) plugin_handler ==> do plug staffs + unmask irq_hpd at end of handler

2) unplug_handler ==> mask both plugin and irq_hpd  + do unplug staffs + 
unmask plugin irq at end of handler

3) priority order of handling irq when multiple irqs pending ==> plugin 
-> irq_hpd -> unplug

>
>> I will fill up below question with Apple dongle case with the order of
>> event happen timing.
>>
>>> I'll write out the various scenarios
>>>
>>> #1
>>>        dongle plugged in with HDMI cable attached
>>>        driver probe
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) generate plugged-in interrupt triggers handler
>> 4) dp_display_phy_init() ==> phy_initialized = true;
>>
>>>
>>> #2
>>>        dongle unplugged
>>>        driver probe
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>>
>>
>>> #3
>>>        dongle plugged in without HDMI cable attached
>>>        driver probe
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) generate plug-in interrupt triggers handler
>> 4) dp_display_phy_init() ==> phy_initialized = true;
>>
>> Note: same as case #1
>>> #4
>>>        driver probe
>>>        dongle plugged in without HDMI cable attached
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) dongle plugged in
>> 4) generate plug-in interrupt triggers handler
>> 5) dp_display_phy_init() ==> phy_initialized = true;
>>
>>>
>>> #5
>>>        driver probe
>>>        dongle plugged in with HDMI cable attached
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) dongle plugged in
>> 4) generate plug-in interrupt trigger handler
>> 5) dp_display_phy_init() ==> phy_initialized = true;
>>
>> Note: same as case #4
>>
>>> #6
>>>        driver probe
>>>        dongle plugged in
>>>        suspend
>>>        resume
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) dongle plug in
>> 4) generate plug-in interrupt triggers handler
>> 5) dp_display_phy_init() ==> phy_initialized = true;
>> 6) suspend
>> 7) dp_display_host_deinit() ==> core_initialized = false;
>> 8) dp_display_host_phy_exit() ==> phy_initialize = false;
>> 9) resume
>> 10) dp_display_host_init() ==> core_initialized = true;
>> 11) generate plug-in interrupt
>> 12) dp_display_phy_init() ==> phy_initialize = true;
>>
>>> #7
>>>        driver probe
>>>        dongle plugged in
>>>        suspend
>>>        dongle unplugged
>>>        resume
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) dongle plugged in
>> 4) generate plug-in interrupt triggers handler
>> 5) dp_display_phy_init() ==> phy_initialized = true;
>> 6) suspend
>> 7) dp_display_host_deinit() ==> core_initialized = false;
>> 8) dp_display_host_phy_exit() ==> phy_initialize = false;
> Why is the order of operations swapped? During probe core_initialized
> is done first and then phy_initialized but then on suspend
> core_initialized is done first again before phy_initialized. That's
> asymmetric.
ok, will fix this
>
>> 9) dongle unplugged
>> 10) resume
>> 11) dp_display_host_init() ==> core_initialized = true;
>>
>> #8
>>          driver probe
>>          dongle plugged in without HDMI cable attached
>>          suspend
>>          resume
>>
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) dongle plug in
>> 4) generate plug-in interrupt triggers handler
>> 5) dp_display_phy_init() ==> phy_initialized = true;
>> 6) suspend
>> 7) dp_display_host_deinit() ==> core_initialized = false;
>> 8) dp_display_host_phy_exit() ==> phy_initialize = false;
>> 9) resume
>> 10) dp_display_host_init() ==> core_initialized = true;
>> 11) generate plug-in interrupt
>> 12) dp_display_phy_init() ==> phy_initialize = true;
>>
>>
>> NOTE: same case #6
>>
>> #9
>>          driver probe
>>          dongle plugged in without HDMI cable attached
>>          suspend
>>          HDMI cable attached during suspend
>>          resume
>>
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) dongle plugged in
>> 4) generate plug-in interrupt triggers handler
>> 5) dp_display_phy_init() ==> phy_initialized = true;
>> 6) suspend
>> 7) dp_display_host_deinit() ==> core_initialized = false;
>> 8) dp_display_host_phy_exit() ==> phy_initialize = false;
>> 9) HDMI cable attached
>> 10) resume
>> 11) dp_display_host_init() ==> core_initialized = true;
>> 12) generate plug-in interrupt
>> 13) dp_display_phy_init() ==> phy_initialize = true;
>>
>>
>> What's the state of the phy and core initialized variable at the end of
>> each of these scenarios? Please fill out the truth table.
>>
>>                    +-----------------+------------------------
>>                     |    false        |       true            |
>>                    +-----------------+------------------------
>>    phy_initialized  |                 |                       |
>>                    +-----------------+------------------------
>>    core_initialized |                 | #1,                   |
>>                    +-----------------+------------------------
>>
>> I guess we also need eDP scenarios, but that's probably simpler
>>
>> #10
>>          eDP panel connected
>>          driver probe
>>
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) generate plug-in interrupt triggers handler
> I think this is more like "dp_display_config_hpd() is called by hpd
> kthread"?

yes, correct as below (eDP will call phy_init immediately

1) driver probe ==> core_initialized = false;    phy_initialized = false;
2) dp_display_config_hpd()
3) dp_display_host_init() ==> core_initialized = true;
4) dp_display_host_phy_init() ==> phy_initialize = true
5) generate plug-in interrupt triggers handler

>
>> 4) dp_display_phy_init() ==> phy_initialized = true;
>>
>>
>>
>> #11
>>          eDP panel disconnected
>>          driver probe
>>
>> NOTE: eDP panel can not be disconnected
> The panel can certainly be disconnected in the sense that the ribbon
> cable to the panel is busted or not working properly. That's what this
> scenario is for.

1) driver probe ==> core_initialized = false;    phy_initialized = false;
2) dp_display_config_hpd()
3) dp_display_host_init() ==> core_initialized = true;
4) dp_display_host_phy_init() ==> phy_initialize = true

1) driver probe ==> core_initialized = false; phy_initialized = false;
>> #12
>>          eDP panel disconnected
>>          driver probe
>>          suspend
>>          resume
>>
>> NOTE: assume edp panel connected
>> 1) driver probe ==> core_initialized = false;    phy_initialized = false;
>> 2) dp_display_host_init() ==> core_initialized = true;
>> 3) generate plug-in interrupt triggers handler
>> 4) dp_display_phy_init() ==> phy_initialized = true;
>> 5) suspend
>> 6) dp_display_host_deinit() ==> core_initialized = false;
>> 7) dp_display_host_phy_exit() ==> phy_initialize = false;
>> 8) resume
>> 9) dp_display_host_init() ==> core_initialized = true;
>> 10) generate plug-in interrupt
>> 11) dp_display_phy_init() ==> phy_initialize = true;

1) driver probe ==> core_initialized = false;    phy_initialized = false;
2) dp_display_config_hpd()
3) dp_display_host_init() ==> core_initialized = true;
4) dp_display_host_phy_init() ==> phy_initialize = true
5) generate plug-in interrupt triggers handler
6) dp_display_phy_init() ==> phy_initialized = true;
7) suspend
8) dp_display_host_deinit() ==> core_initialized = false;
9) dp_display_host_phy_exit() ==> phy_initialize = false;
10) resume
11) dp_display_host_init() ==> core_initialized = true;
11) dp_display_phy_init() ==> phy_initialize = true;
12) generate plug-in interrupt triggers handler

> Thanks. It really helps to see the various scenarios.
>
>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
>>>> index 7cc4d21..f6bb4bc 100644
>>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
>>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>>>> @@ -83,6 +83,7 @@ struct dp_display_private {
>>>>
>>>>           /* state variables */
>>>>           bool core_initialized;
>>>> +       bool phy_initialized;
>>>>           bool hpd_irq_on;
>>>>           bool audio_supported;
>>>>
>>>> @@ -372,21 +373,46 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
>>>>           return rc;
>>>>    }
>>>>
>>>> -static void dp_display_host_init(struct dp_display_private *dp, int reset)
>>>> +static void dp_display_host_phy_init(struct dp_display_private *dp)
>>>>    {
>>>> -       bool flip = false;
>>>> +       DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
>>>> +                       dp->core_initialized, dp->phy_initialized);
>>>>
>>>> +       if (!dp->phy_initialized) {
>>>> +               dp_ctrl_phy_init(dp->ctrl);
>>>> +               dp->phy_initialized = true;
>>>> +       }
>>>> +}
>>>> +
>>>> +static void dp_display_host_phy_exit(struct dp_display_private *dp)
>>>> +{
>>>> +       DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
>>>> +                       dp->core_initialized, dp->phy_initialized);
>>>> +
>>>> +       if (dp->phy_initialized) {
>>>> +               dp_ctrl_phy_exit(dp->ctrl);
>>>> +               dp->phy_initialized = false;
>>>> +       }
>>>> +}
>>>> +
>>>> +static void dp_display_host_init(struct dp_display_private *dp)
>>>> +{
>>>>           DRM_DEBUG_DP("core_initialized=%d\n", dp->core_initialized);
>>>>           if (dp->core_initialized) {
>>>>                   DRM_DEBUG_DP("DP core already initialized\n");
>>>>                   return;
>>>>           }
>>>>
>>>> -       if (dp->usbpd->orientation == ORIENTATION_CC2)
>>>> -               flip = true;
>>>> +       dp_power_init(dp->power, false);
>>>> +       dp_ctrl_reset_irq_ctrl(dp->ctrl, true);
>>>> +
>>>> +       /*
>>>> +        * eDP is the embedded primary display and has its own phy
>>>> +        * initialize phy immediately
>>> Question still stands why we can't wait for hpd high from the eDP panel.
>>> Also, I think "has its own phy" means that it's not part of a combo
>>> USB+DP phy? Can you please clarify?
>>>
>>>> +        */
>>>> +       if (dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP)
>>>> +               dp_display_host_phy_init(dp);
>>>>
>>>> -       dp_power_init(dp->power, flip);
>>>> -       dp_ctrl_host_init(dp->ctrl, flip, reset);
>>>>           dp_aux_init(dp->aux);
>>>>           dp->core_initialized = true;
>>>>    }
>>>> @@ -1306,20 +1330,23 @@ static int dp_pm_resume(struct device *dev)
>>>>           dp->hpd_state = ST_DISCONNECTED;
>>>>
>>>>           /* turn on dp ctrl/phy */
>>>> -       dp_display_host_init(dp, true);
>>>> +       dp_display_host_init(dp);
>>>>
>>>>           dp_catalog_ctrl_hpd_config(dp->catalog);
>>>>
>>>> -       /*
>>>> -        * set sink to normal operation mode -- D0
>>>> -        * before dpcd read
>>>> -        */
>>>> -       dp_link_psm_config(dp->link, &dp->panel->link_info, false);
>>>>
>>>>           if (dp_catalog_link_is_connected(dp->catalog)) {
>>>> +               /*
>>>> +                * set sink to normal operation mode -- D0
>>>> +                * before dpcd read
>>>> +                */
>>>> +               dp_display_host_phy_init(dp);
>>>> +               dp_link_psm_config(dp->link, &dp->panel->link_info, false);
>>>>                   sink_count = drm_dp_read_sink_count(dp->aux);
>>>>                   if (sink_count < 0)
>>>>                           sink_count = 0;
>>>> +
>>>> +               dp_display_host_phy_exit(dp);
>>> Why is the phy exited on resume when the link is still connected? Is
>>> this supposed to be done only when the sink_count is 0? And how does
>>> this interact with eDP where the phy is initialized by the call to
>>> dp_display_host_init() earlier in this function.
>>>
>>>>           }
>>>>
>>>>           dp->link->sink_count = sink_count;
> Any response to the above two comments?

  reply	other threads:[~2022-01-13 17:51 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-11 18:43 [PATCH v11 0/4] group dp driver related patches into one series Kuogee Hsieh
2022-01-11 18:43 ` [PATCH v11 1/4] drm/msm/dp: do not initialize phy until plugin interrupt received Kuogee Hsieh
2022-01-12 20:00   ` Stephen Boyd
2022-01-12 22:17     ` Kuogee Hsieh
2022-01-13  4:13       ` Stephen Boyd
2022-01-13 17:51         ` Kuogee Hsieh [this message]
2022-01-13 19:47           ` Stephen Boyd
2022-01-13 20:44             ` Kuogee Hsieh
2022-01-13 21:52               ` Stephen Boyd
2022-01-13 22:14                 ` Kuogee Hsieh
2022-01-13 23:13                   ` Stephen Boyd
2022-01-11 18:43 ` [PATCH v11 2/4] drm/msm/dp: populate connector of struct dp_panel Kuogee Hsieh
2022-01-11 18:43 ` [PATCH v11 3/4] drm/msm/dp: add support of tps4 (training pattern 4) for HBR3 Kuogee Hsieh
2022-01-11 18:43 ` [PATCH v11 4/4] drm/msm/dp: stop link training after link training 2 failed Kuogee Hsieh

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=338ae657-e8ed-e620-0aa7-4ad05df18ad1@quicinc.com \
    --to=quic_khsieh@quicinc.com \
    --cc=agross@kernel.org \
    --cc=airlied@linux.ie \
    --cc=aravindh@codeaurora.org \
    --cc=bjorn.andersson@linaro.org \
    --cc=daniel@ffwll.ch \
    --cc=dmitry.baryshkov@linaro.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=freedreno@lists.freedesktop.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=quic_abhinavk@quicinc.com \
    --cc=quic_sbillaka@quicinc.com \
    --cc=robdclark@gmail.com \
    --cc=sean@poorly.run \
    --cc=swboyd@chromium.org \
    --cc=vkoul@kernel.org \
    /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

all inboxes | Powered by JetHome®