Message ID | 1695848028-18023-8-git-send-email-quic_khsieh@quicinc.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:cae8:0:b0:403:3b70:6f57 with SMTP id r8csp2911019vqu; Wed, 27 Sep 2023 14:31:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGVayANSg2Yd8xRwKa/94EyNC0lrTzPL+BvOrMHdcSqR2P7aoquGMSAbf4ZtpS5Ke/ePwjn X-Received: by 2002:a17:90b:38cd:b0:271:78a0:8ab2 with SMTP id nn13-20020a17090b38cd00b0027178a08ab2mr9900280pjb.24.1695850302829; Wed, 27 Sep 2023 14:31:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695850302; cv=none; d=google.com; s=arc-20160816; b=b96acTnAOhN+oK2jD4hzAwcvUdMBxMCcnXidlosCQEm2nyXT2fiEDugUx4uB5h9de/ 4lfpO8IliTY9KqtG6XhifTvi9xTrYWGZ10tHgxHwr+bds054kFGKb1GFzPAbMpgG0r/F agl6WN0r4bXSZoFS+muUnWTUxXBidq4y90isEiRZrogQ4UaFPa28j17bbQeOXpBj+ZYi PGfQVke7IKBGAAOdaO+TEmzvFpYwfZwM48MSxZjyPOkOt4ZOEurD6ZJn/fxTLguL4fVi 4WZO6zxii1u9l++XQQ5iSdEgHjK0tGwpaioQqlQWP2PplwmMy/GPuvfMK0jl9RkrNEQp 5knw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=9a+/WMRmVoVO3fhRoKc8WHoZzcWwvB2xv3lI6f3C6r8=; fh=WdvorNt9W2LCUPiGPsn75/bW5381IkpXRxF82JgZV7c=; b=bp9LEbQOtHzNIH3frof0OuHDzCdVSCmcJg4BffoOVaOcZAAXkR85ku7IQUvb6EprIx W+lCTGx/YnpV+9Y4hPJ2mYWrkGcms0U7KMrlxDkFEP72muWtePg6TFSsW4Rv+o8mO3M7 jyec/o7dxyggoSsCtmXX+UZo8aXxzn6OJ/y7iJwQraGdj5Hb4t3y2Ph9z51ftF6ubhjQ UBrZ4ZjEuirNmqe9sClTCW+PAeZO+Q+ZRxlGbNGjAYRYKFV2CPHopmE/n7zhYqCTY90Q dp3P/Gobb5NZuvTOFgP776/o81IWgwcr2HDmz49vztOK8HVh87bCV+7q5HfzKLdEtYVw KRjw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@quicinc.com header.s=qcppdkim1 header.b=j2XfStHS; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=quicinc.com Received: from agentk.vger.email (agentk.vger.email. [2620:137:e000::3:2]) by mx.google.com with ESMTPS id lw16-20020a17090b181000b00263860e1f4csi11590204pjb.16.2023.09.27.14.31.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Sep 2023 14:31:42 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) client-ip=2620:137:e000::3:2; Authentication-Results: mx.google.com; dkim=pass header.i=@quicinc.com header.s=qcppdkim1 header.b=j2XfStHS; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=quicinc.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id 64E70804C212; Wed, 27 Sep 2023 13:55:09 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229998AbjI0Uyr (ORCPT <rfc822;ruipengqi7@gmail.com> + 20 others); Wed, 27 Sep 2023 16:54:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51536 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229772AbjI0Uyb (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Wed, 27 Sep 2023 16:54:31 -0400 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A566126; Wed, 27 Sep 2023 13:54:29 -0700 (PDT) Received: from pps.filterd (m0279866.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 38RKFTXk012530; Wed, 27 Sep 2023 20:54:10 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=9a+/WMRmVoVO3fhRoKc8WHoZzcWwvB2xv3lI6f3C6r8=; b=j2XfStHSTEMh4Cjn/HeILLkK7TVzWoko6iXoLEwNWhxuJ9dPTVpVBM3XCN8AUi66OMV4 Y+zdVim5fXA9RFLaZnUnROdAAklfE7Cd/lXaThpD0ZdNbvQGafJeamBUPjFH3tmeaTzx BRHW810lIXNR0llsl6k7r1kwZKkw7+IhknZ47ZXbvJcuGz8xM7Q208azD3hu9DbS49Bs /T+NstCRBKHZP4zo/ep2Ivqhv6L1yH70SCwEY/9vVK5KOiIzXsyRlS19SawgNAuSYu23 dkgIupX9XgYfEqNjmrau6Zb0y0e28uSAO2+LKo4sf59SqBFAuTlecuat5ZBACmTwni5g cA== Received: from nalasppmta02.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3tct5gr6b2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 27 Sep 2023 20:54:09 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA02.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 38RKs9Vd028921 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 27 Sep 2023 20:54:09 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.36; Wed, 27 Sep 2023 13:54:08 -0700 From: Kuogee Hsieh <quic_khsieh@quicinc.com> To: <dri-devel@lists.freedesktop.org>, <robdclark@gmail.com>, <sean@poorly.run>, <swboyd@chromium.org>, <dianders@chromium.org>, <vkoul@kernel.org>, <daniel@ffwll.ch>, <airlied@gmail.com>, <agross@kernel.org>, <dmitry.baryshkov@linaro.org>, <andersson@kernel.org> CC: Kuogee Hsieh <quic_khsieh@quicinc.com>, <quic_abhinavk@quicinc.com>, <quic_jesszhan@quicinc.com>, <quic_sbillaka@quicinc.com>, <marijn.suijten@somainline.org>, <freedreno@lists.freedesktop.org>, <linux-arm-msm@vger.kernel.org>, <linux-kernel@vger.kernel.org> Subject: [PATCH v4 7/8] drm/msm/dp: add pm_runtime_force_suspend()/resume() Date: Wed, 27 Sep 2023 13:53:47 -0700 Message-ID: <1695848028-18023-8-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1695848028-18023-1-git-send-email-quic_khsieh@quicinc.com> References: <1695848028-18023-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: 47Ojmjz55pXuYqva2zIkTd-XpY07A5o2 X-Proofpoint-GUID: 47Ojmjz55pXuYqva2zIkTd-XpY07A5o2 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.980,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2023-09-27_13,2023-09-27_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 malwarescore=0 mlxlogscore=999 impostorscore=0 phishscore=0 adultscore=0 suspectscore=0 priorityscore=1501 mlxscore=0 bulkscore=0 clxscore=1015 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2309180000 definitions=main-2309270178 X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Wed, 27 Sep 2023 13:55:09 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1778227927120393315 X-GMAIL-MSGID: 1778227927120393315 |
Series |
incorporate pm runtime framework and eDP clean up
|
|
Commit Message
Kuogee Hsieh
Sept. 27, 2023, 8:53 p.m. UTC
After incorporated pm_runtime framework into eDP/DP driver, the
original dp_pm_suspend() to handle power off both DP phy and
controller during suspend and dp_pm_resume() to handle power on
both DP phy and controller during resume are not necessary since
those function are replaced by dp_pm_runtime_suspend() and
dp_pm_runtime_resume() through pm runtime framework.
Therefore add pm framework provides functions,
pm_runtime_force_suspend()/resume() to complete incorporating pm
runtime framework into DP driver.
Changes in v4:
-- drop both dp_pm_prepare() and dp_pm_compete() from this change
-- delete ST_SUSPENDED state
-- rewording commit text to add more details regrading the purpose
of this change
Changes in v3:
-- replace dp_pm_suspend() with pm_runtime_force_suspend()
-- replace dp_pm_resume() with pm_runtime_force_resume()
Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
drivers/gpu/drm/msm/dp/dp_display.c | 113 ++----------------------------------
1 file changed, 5 insertions(+), 108 deletions(-)
Comments
On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: > > After incorporated pm_runtime framework into eDP/DP driver, the incorporating > original dp_pm_suspend() to handle power off both DP phy and > controller during suspend and dp_pm_resume() to handle power on > both DP phy and controller during resume are not necessary since > those function are replaced by dp_pm_runtime_suspend() and > dp_pm_runtime_resume() through pm runtime framework. > Therefore add pm framework provides functions, > pm_runtime_force_suspend()/resume() to complete incorporating pm > runtime framework into DP driver. > > Changes in v4: > -- drop both dp_pm_prepare() and dp_pm_compete() from this change > -- delete ST_SUSPENDED state > -- rewording commit text to add more details regrading the purpose > of this change > > Changes in v3: > -- replace dp_pm_suspend() with pm_runtime_force_suspend() > -- replace dp_pm_resume() with pm_runtime_force_resume() > > Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> > --- > drivers/gpu/drm/msm/dp/dp_display.c | 113 ++---------------------------------- > 1 file changed, 5 insertions(+), 108 deletions(-) > > diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c > index 9158a2c..711d262 100644 > --- a/drivers/gpu/drm/msm/dp/dp_display.c > +++ b/drivers/gpu/drm/msm/dp/dp_display.c > @@ -49,7 +49,6 @@ enum { > ST_CONNECTED, > ST_DISCONNECT_PENDING, > ST_DISPLAY_OFF, > - ST_SUSPENDED, > }; > > enum { > @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) > drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", > dp->dp_display.connector_type, state); > > - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { > + if (state == ST_DISPLAY_OFF) { > mutex_unlock(&dp->event_mutex); > return 0; > } > @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) > drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", > dp->dp_display.connector_type, state); > > - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { > + if (state == ST_DISPLAY_OFF) { > mutex_unlock(&dp->event_mutex); > return 0; > } > @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) > return 0; > } > > -static int dp_pm_resume(struct device *dev) > -{ > - struct platform_device *pdev = to_platform_device(dev); > - struct msm_dp *dp_display = platform_get_drvdata(pdev); > - struct dp_display_private *dp; > - int sink_count = 0; > - > - dp = container_of(dp_display, struct dp_display_private, dp_display); > - > - mutex_lock(&dp->event_mutex); > - > - drm_dbg_dp(dp->drm_dev, > - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > - dp->dp_display.connector_type, dp->core_initialized, > - dp->phy_initialized, dp_display->power_on); > - > - /* start from disconnected state */ > - dp->hpd_state = ST_DISCONNECTED; > - > - /* turn on dp ctrl/phy */ > - dp_display_host_init(dp); > - > - if (dp_display->is_edp) > - dp_catalog_ctrl_hpd_enable(dp->catalog); > - > - 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); > - } > - > - dp->link->sink_count = sink_count; > - /* > - * can not declared display is connected unless > - * HDMI cable is plugged in and sink_count of > - * dongle become 1 > - * also only signal audio when disconnected > - */ > - if (dp->link->sink_count) { > - dp->dp_display.link_ready = true; > - } else { > - dp->dp_display.link_ready = false; > - dp_display_handle_plugged_change(dp_display, false); > - } > - > - drm_dbg_dp(dp->drm_dev, > - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", > - dp->dp_display.connector_type, dp->link->sink_count, > - dp->dp_display.link_ready, dp->core_initialized, > - dp->phy_initialized, dp_display->power_on); > - > - mutex_unlock(&dp->event_mutex); > - > - return 0; > -} > - > -static int dp_pm_suspend(struct device *dev) > -{ > - struct platform_device *pdev = to_platform_device(dev); > - struct msm_dp *dp_display = platform_get_drvdata(pdev); > - struct dp_display_private *dp; > - > - dp = container_of(dp_display, struct dp_display_private, dp_display); > - > - mutex_lock(&dp->event_mutex); > - > - drm_dbg_dp(dp->drm_dev, > - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > - dp->dp_display.connector_type, dp->core_initialized, > - dp->phy_initialized, dp_display->power_on); > - > - /* mainlink enabled */ > - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) > - dp_ctrl_off_link_stream(dp->ctrl); > - > - dp_display_host_phy_exit(dp); I was under the impression that dp_pm_runtime_suspend / _resume functions perform phy init/exit only in eDP cases. Can we really drop the main suspend/resume functions? > - > - /* host_init will be called at pm_resume */ > - dp_display_host_deinit(dp); > - > - dp->hpd_state = ST_SUSPENDED; > - > - drm_dbg_dp(dp->drm_dev, > - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > - dp->dp_display.connector_type, dp->core_initialized, > - dp->phy_initialized, dp_display->power_on); > - > - mutex_unlock(&dp->event_mutex); > - > - return 0; > -} > - > static const struct dev_pm_ops dp_pm_ops = { > SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) > - .suspend = dp_pm_suspend, > - .resume = dp_pm_resume, > + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, > + pm_runtime_force_resume) > }; > > static struct platform_driver dp_display_driver = { > @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, > > dp_display = container_of(dp, struct dp_display_private, dp_display); > > - if (dp->is_edp) > - dp_hpd_unplug_handle(dp_display, 0); Why? > - > mutex_lock(&dp_display->event_mutex); > > state = dp_display->hpd_state; > @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) > dp_catalog_ctrl_hpd_disable(dp->catalog); > > dp_display->internal_hpd = false; > + dp->hpd_state = ST_DISCONNECTED; Why? We have only disabled sending of the HPD events. The dongle might still be connected. > > pm_runtime_mark_last_busy(&dp->pdev->dev); > pm_runtime_put_autosuspend(&dp->pdev->dev); > -- > 2.7.4 > -- With best wishes Dmitry
On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote: > On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: >> After incorporated pm_runtime framework into eDP/DP driver, the > incorporating > > >> original dp_pm_suspend() to handle power off both DP phy and >> controller during suspend and dp_pm_resume() to handle power on >> both DP phy and controller during resume are not necessary since >> those function are replaced by dp_pm_runtime_suspend() and >> dp_pm_runtime_resume() through pm runtime framework. >> Therefore add pm framework provides functions, >> pm_runtime_force_suspend()/resume() to complete incorporating pm >> runtime framework into DP driver. >> >> Changes in v4: >> -- drop both dp_pm_prepare() and dp_pm_compete() from this change >> -- delete ST_SUSPENDED state >> -- rewording commit text to add more details regrading the purpose >> of this change >> >> Changes in v3: >> -- replace dp_pm_suspend() with pm_runtime_force_suspend() >> -- replace dp_pm_resume() with pm_runtime_force_resume() >> >> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> >> --- >> drivers/gpu/drm/msm/dp/dp_display.c | 113 ++---------------------------------- >> 1 file changed, 5 insertions(+), 108 deletions(-) >> >> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c >> index 9158a2c..711d262 100644 >> --- a/drivers/gpu/drm/msm/dp/dp_display.c >> +++ b/drivers/gpu/drm/msm/dp/dp_display.c >> @@ -49,7 +49,6 @@ enum { >> ST_CONNECTED, >> ST_DISCONNECT_PENDING, >> ST_DISPLAY_OFF, >> - ST_SUSPENDED, >> }; >> >> enum { >> @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) >> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", >> dp->dp_display.connector_type, state); >> >> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { >> + if (state == ST_DISPLAY_OFF) { >> mutex_unlock(&dp->event_mutex); >> return 0; >> } >> @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) >> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", >> dp->dp_display.connector_type, state); >> >> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { >> + if (state == ST_DISPLAY_OFF) { >> mutex_unlock(&dp->event_mutex); >> return 0; >> } >> @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) >> return 0; >> } >> >> -static int dp_pm_resume(struct device *dev) >> -{ >> - struct platform_device *pdev = to_platform_device(dev); >> - struct msm_dp *dp_display = platform_get_drvdata(pdev); >> - struct dp_display_private *dp; >> - int sink_count = 0; >> - >> - dp = container_of(dp_display, struct dp_display_private, dp_display); >> - >> - mutex_lock(&dp->event_mutex); >> - >> - drm_dbg_dp(dp->drm_dev, >> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >> - dp->dp_display.connector_type, dp->core_initialized, >> - dp->phy_initialized, dp_display->power_on); >> - >> - /* start from disconnected state */ >> - dp->hpd_state = ST_DISCONNECTED; >> - >> - /* turn on dp ctrl/phy */ >> - dp_display_host_init(dp); >> - >> - if (dp_display->is_edp) >> - dp_catalog_ctrl_hpd_enable(dp->catalog); >> - >> - 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); >> - } >> - >> - dp->link->sink_count = sink_count; >> - /* >> - * can not declared display is connected unless >> - * HDMI cable is plugged in and sink_count of >> - * dongle become 1 >> - * also only signal audio when disconnected >> - */ >> - if (dp->link->sink_count) { >> - dp->dp_display.link_ready = true; >> - } else { >> - dp->dp_display.link_ready = false; >> - dp_display_handle_plugged_change(dp_display, false); >> - } >> - >> - drm_dbg_dp(dp->drm_dev, >> - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", >> - dp->dp_display.connector_type, dp->link->sink_count, >> - dp->dp_display.link_ready, dp->core_initialized, >> - dp->phy_initialized, dp_display->power_on); >> - >> - mutex_unlock(&dp->event_mutex); >> - >> - return 0; >> -} >> - >> -static int dp_pm_suspend(struct device *dev) >> -{ >> - struct platform_device *pdev = to_platform_device(dev); >> - struct msm_dp *dp_display = platform_get_drvdata(pdev); >> - struct dp_display_private *dp; >> - >> - dp = container_of(dp_display, struct dp_display_private, dp_display); >> - >> - mutex_lock(&dp->event_mutex); >> - >> - drm_dbg_dp(dp->drm_dev, >> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >> - dp->dp_display.connector_type, dp->core_initialized, >> - dp->phy_initialized, dp_display->power_on); >> - >> - /* mainlink enabled */ >> - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) >> - dp_ctrl_off_link_stream(dp->ctrl); >> - >> - dp_display_host_phy_exit(dp); > I was under the impression that dp_pm_runtime_suspend / _resume > functions perform phy init/exit only in eDP cases. Can we really drop > the main suspend/resume functions? yes on eDP case since it is embedded. for external DP case, there are two steps step 1: enable DP controller's hpd block and start waiting for hpd interrupts at dp_display_hpd_enable() step 2: at plugin interrupts, dp_display_host_phy_init() step 3: at unplug interrupt: dp_bridge_atomic_post_disable() dp_display_host_phy_exi() at runtime, there is loop between step 2 and step 3 step 4: disable DP controller's hpd block > >> - >> - /* host_init will be called at pm_resume */ >> - dp_display_host_deinit(dp); >> - >> - dp->hpd_state = ST_SUSPENDED; >> - >> - drm_dbg_dp(dp->drm_dev, >> - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >> - dp->dp_display.connector_type, dp->core_initialized, >> - dp->phy_initialized, dp_display->power_on); >> - >> - mutex_unlock(&dp->event_mutex); >> - >> - return 0; >> -} >> - >> static const struct dev_pm_ops dp_pm_ops = { >> SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) >> - .suspend = dp_pm_suspend, >> - .resume = dp_pm_resume, >> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, >> + pm_runtime_force_resume) >> }; >> >> static struct platform_driver dp_display_driver = { >> @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, >> >> dp_display = container_of(dp, struct dp_display_private, dp_display); >> >> - if (dp->is_edp) >> - dp_hpd_unplug_handle(dp_display, 0); > Why? dp_hpd_unplug_handle() does not tear down phy. Therefore eDP does not need to call unplug handle. >> - >> mutex_lock(&dp_display->event_mutex); >> >> state = dp_display->hpd_state; >> @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) >> dp_catalog_ctrl_hpd_disable(dp->catalog); >> >> dp_display->internal_hpd = false; >> + dp->hpd_state = ST_DISCONNECTED; > Why? We have only disabled sending of the HPD events. The dongle might > still be connected. dp_bridge_hpd_disable() disable dp controller hpd block (no more hpd interrupt will be received). dp_bridge_hpd_disable() should happen after DP main link had been teared down already. Therefore hpd_state need to be in default state so that next plugin handle will be start with correct state. > >> pm_runtime_mark_last_busy(&dp->pdev->dev); >> pm_runtime_put_autosuspend(&dp->pdev->dev); >> -- >> 2.7.4 >> > > -- > With best wishes > > Dmitry
On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: > > > On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote: > > On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: > >> After incorporated pm_runtime framework into eDP/DP driver, the > > incorporating > > > > > >> original dp_pm_suspend() to handle power off both DP phy and > >> controller during suspend and dp_pm_resume() to handle power on > >> both DP phy and controller during resume are not necessary since > >> those function are replaced by dp_pm_runtime_suspend() and > >> dp_pm_runtime_resume() through pm runtime framework. > >> Therefore add pm framework provides functions, > >> pm_runtime_force_suspend()/resume() to complete incorporating pm > >> runtime framework into DP driver. > >> > >> Changes in v4: > >> -- drop both dp_pm_prepare() and dp_pm_compete() from this change > >> -- delete ST_SUSPENDED state > >> -- rewording commit text to add more details regrading the purpose > >> of this change > >> > >> Changes in v3: > >> -- replace dp_pm_suspend() with pm_runtime_force_suspend() > >> -- replace dp_pm_resume() with pm_runtime_force_resume() > >> > >> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> > >> --- > >> drivers/gpu/drm/msm/dp/dp_display.c | 113 ++---------------------------------- > >> 1 file changed, 5 insertions(+), 108 deletions(-) > >> > >> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c > >> index 9158a2c..711d262 100644 > >> --- a/drivers/gpu/drm/msm/dp/dp_display.c > >> +++ b/drivers/gpu/drm/msm/dp/dp_display.c > >> @@ -49,7 +49,6 @@ enum { > >> ST_CONNECTED, > >> ST_DISCONNECT_PENDING, > >> ST_DISPLAY_OFF, > >> - ST_SUSPENDED, > >> }; > >> > >> enum { > >> @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) > >> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", > >> dp->dp_display.connector_type, state); > >> > >> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { > >> + if (state == ST_DISPLAY_OFF) { > >> mutex_unlock(&dp->event_mutex); > >> return 0; > >> } > >> @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) > >> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", > >> dp->dp_display.connector_type, state); > >> > >> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { > >> + if (state == ST_DISPLAY_OFF) { > >> mutex_unlock(&dp->event_mutex); > >> return 0; > >> } > >> @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) > >> return 0; > >> } > >> > >> -static int dp_pm_resume(struct device *dev) > >> -{ > >> - struct platform_device *pdev = to_platform_device(dev); > >> - struct msm_dp *dp_display = platform_get_drvdata(pdev); > >> - struct dp_display_private *dp; > >> - int sink_count = 0; > >> - > >> - dp = container_of(dp_display, struct dp_display_private, dp_display); > >> - > >> - mutex_lock(&dp->event_mutex); > >> - > >> - drm_dbg_dp(dp->drm_dev, > >> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > >> - dp->dp_display.connector_type, dp->core_initialized, > >> - dp->phy_initialized, dp_display->power_on); > >> - > >> - /* start from disconnected state */ > >> - dp->hpd_state = ST_DISCONNECTED; > >> - > >> - /* turn on dp ctrl/phy */ > >> - dp_display_host_init(dp); > >> - > >> - if (dp_display->is_edp) > >> - dp_catalog_ctrl_hpd_enable(dp->catalog); > >> - > >> - 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); > >> - } > >> - > >> - dp->link->sink_count = sink_count; > >> - /* > >> - * can not declared display is connected unless > >> - * HDMI cable is plugged in and sink_count of > >> - * dongle become 1 > >> - * also only signal audio when disconnected > >> - */ > >> - if (dp->link->sink_count) { > >> - dp->dp_display.link_ready = true; > >> - } else { > >> - dp->dp_display.link_ready = false; > >> - dp_display_handle_plugged_change(dp_display, false); > >> - } > >> - > >> - drm_dbg_dp(dp->drm_dev, > >> - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", > >> - dp->dp_display.connector_type, dp->link->sink_count, > >> - dp->dp_display.link_ready, dp->core_initialized, > >> - dp->phy_initialized, dp_display->power_on); > >> - > >> - mutex_unlock(&dp->event_mutex); > >> - > >> - return 0; > >> -} > >> - > >> -static int dp_pm_suspend(struct device *dev) > >> -{ > >> - struct platform_device *pdev = to_platform_device(dev); > >> - struct msm_dp *dp_display = platform_get_drvdata(pdev); > >> - struct dp_display_private *dp; > >> - > >> - dp = container_of(dp_display, struct dp_display_private, dp_display); > >> - > >> - mutex_lock(&dp->event_mutex); > >> - > >> - drm_dbg_dp(dp->drm_dev, > >> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > >> - dp->dp_display.connector_type, dp->core_initialized, > >> - dp->phy_initialized, dp_display->power_on); > >> - > >> - /* mainlink enabled */ > >> - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) > >> - dp_ctrl_off_link_stream(dp->ctrl); > >> - > >> - dp_display_host_phy_exit(dp); > > I was under the impression that dp_pm_runtime_suspend / _resume > > functions perform phy init/exit only in eDP cases. Can we really drop > > the main suspend/resume functions? > > yes on eDP case since it is embedded. Let me ask the same question in a different way: dp_pm_suspend() / dp_pm_resume() functions contain several calls to DP functions. Why can we drop them now? Maybe they had to be dropped in one of the previous patches, when you have added proper runtime PM support? Could you please confirm that after each patch the DP driver is working, that there are no hidden dependencies between patches? > for external DP case, there are two steps > > step 1: enable DP controller's hpd block and start waiting for hpd > interrupts at dp_display_hpd_enable() Step 1 should be optional. DP should be functional even if the .hpd_enable was not called. Have you tested this usecase? > > step 2: at plugin interrupts, dp_display_host_phy_init() > > step 3: at unplug interrupt: dp_bridge_atomic_post_disable() > dp_display_host_phy_exi() > > at runtime, there is loop between step 2 and step 3 > > step 4: disable DP controller's hpd block > > > > >> - > >> - /* host_init will be called at pm_resume */ > >> - dp_display_host_deinit(dp); > >> - > >> - dp->hpd_state = ST_SUSPENDED; > >> - > >> - drm_dbg_dp(dp->drm_dev, > >> - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > >> - dp->dp_display.connector_type, dp->core_initialized, > >> - dp->phy_initialized, dp_display->power_on); > >> - > >> - mutex_unlock(&dp->event_mutex); > >> - > >> - return 0; > >> -} > >> - > >> static const struct dev_pm_ops dp_pm_ops = { > >> SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) > >> - .suspend = dp_pm_suspend, > >> - .resume = dp_pm_resume, > >> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, > >> + pm_runtime_force_resume) > >> }; > >> > >> static struct platform_driver dp_display_driver = { > >> @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, > >> > >> dp_display = container_of(dp, struct dp_display_private, dp_display); > >> > >> - if (dp->is_edp) > >> - dp_hpd_unplug_handle(dp_display, 0); > > Why? > > dp_hpd_unplug_handle() does not tear down phy. > > Therefore eDP does not need to call unplug handle. I don't fully understand your argument here. Could you please describe, why this function call was necessary beforehand and what is being changed now, so that it becomes unnecessary? > > > > >> - > >> mutex_lock(&dp_display->event_mutex); > >> > >> state = dp_display->hpd_state; > >> @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) > >> dp_catalog_ctrl_hpd_disable(dp->catalog); > >> > >> dp_display->internal_hpd = false; > >> + dp->hpd_state = ST_DISCONNECTED; > > Why? We have only disabled sending of the HPD events. The dongle might > > still be connected. > > dp_bridge_hpd_disable() disable dp controller hpd block (no more hpd > interrupt will be received). > > dp_bridge_hpd_disable() should happen after DP main link had been teared > down already. No, this assumption is incorrect. hpd_disable can happen at any point during runtime. It merely disables HPD interrupt generation, it has nothing to do with the DP block being enabled or not. > Therefore hpd_state need to be in default state so that next plugin > handle will be start with correct state. > > > > > >> pm_runtime_mark_last_busy(&dp->pdev->dev); > >> pm_runtime_put_autosuspend(&dp->pdev->dev); > >> -- > >> 2.7.4 > >> > > > > -- > > With best wishes > > > > Dmitry
On 10/3/2023 10:53 AM, Dmitry Baryshkov wrote: > On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: >> >> On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote: >>> On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: >>>> After incorporated pm_runtime framework into eDP/DP driver, the >>> incorporating >>> >>> >>>> original dp_pm_suspend() to handle power off both DP phy and >>>> controller during suspend and dp_pm_resume() to handle power on >>>> both DP phy and controller during resume are not necessary since >>>> those function are replaced by dp_pm_runtime_suspend() and >>>> dp_pm_runtime_resume() through pm runtime framework. >>>> Therefore add pm framework provides functions, >>>> pm_runtime_force_suspend()/resume() to complete incorporating pm >>>> runtime framework into DP driver. >>>> >>>> Changes in v4: >>>> -- drop both dp_pm_prepare() and dp_pm_compete() from this change >>>> -- delete ST_SUSPENDED state >>>> -- rewording commit text to add more details regrading the purpose >>>> of this change >>>> >>>> Changes in v3: >>>> -- replace dp_pm_suspend() with pm_runtime_force_suspend() >>>> -- replace dp_pm_resume() with pm_runtime_force_resume() >>>> >>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> >>>> --- >>>> drivers/gpu/drm/msm/dp/dp_display.c | 113 ++---------------------------------- >>>> 1 file changed, 5 insertions(+), 108 deletions(-) >>>> >>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c >>>> index 9158a2c..711d262 100644 >>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c >>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c >>>> @@ -49,7 +49,6 @@ enum { >>>> ST_CONNECTED, >>>> ST_DISCONNECT_PENDING, >>>> ST_DISPLAY_OFF, >>>> - ST_SUSPENDED, >>>> }; >>>> >>>> enum { >>>> @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) >>>> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", >>>> dp->dp_display.connector_type, state); >>>> >>>> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { >>>> + if (state == ST_DISPLAY_OFF) { >>>> mutex_unlock(&dp->event_mutex); >>>> return 0; >>>> } >>>> @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) >>>> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", >>>> dp->dp_display.connector_type, state); >>>> >>>> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { >>>> + if (state == ST_DISPLAY_OFF) { >>>> mutex_unlock(&dp->event_mutex); >>>> return 0; >>>> } >>>> @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) >>>> return 0; >>>> } >>>> >>>> -static int dp_pm_resume(struct device *dev) >>>> -{ >>>> - struct platform_device *pdev = to_platform_device(dev); >>>> - struct msm_dp *dp_display = platform_get_drvdata(pdev); >>>> - struct dp_display_private *dp; >>>> - int sink_count = 0; >>>> - >>>> - dp = container_of(dp_display, struct dp_display_private, dp_display); >>>> - >>>> - mutex_lock(&dp->event_mutex); >>>> - >>>> - drm_dbg_dp(dp->drm_dev, >>>> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >>>> - dp->dp_display.connector_type, dp->core_initialized, >>>> - dp->phy_initialized, dp_display->power_on); >>>> - >>>> - /* start from disconnected state */ >>>> - dp->hpd_state = ST_DISCONNECTED; >>>> - >>>> - /* turn on dp ctrl/phy */ >>>> - dp_display_host_init(dp); >>>> - >>>> - if (dp_display->is_edp) >>>> - dp_catalog_ctrl_hpd_enable(dp->catalog); >>>> - >>>> - 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); >>>> - } >>>> - >>>> - dp->link->sink_count = sink_count; >>>> - /* >>>> - * can not declared display is connected unless >>>> - * HDMI cable is plugged in and sink_count of >>>> - * dongle become 1 >>>> - * also only signal audio when disconnected >>>> - */ >>>> - if (dp->link->sink_count) { >>>> - dp->dp_display.link_ready = true; >>>> - } else { >>>> - dp->dp_display.link_ready = false; >>>> - dp_display_handle_plugged_change(dp_display, false); >>>> - } >>>> - >>>> - drm_dbg_dp(dp->drm_dev, >>>> - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", >>>> - dp->dp_display.connector_type, dp->link->sink_count, >>>> - dp->dp_display.link_ready, dp->core_initialized, >>>> - dp->phy_initialized, dp_display->power_on); >>>> - >>>> - mutex_unlock(&dp->event_mutex); >>>> - >>>> - return 0; >>>> -} >>>> - >>>> -static int dp_pm_suspend(struct device *dev) >>>> -{ >>>> - struct platform_device *pdev = to_platform_device(dev); >>>> - struct msm_dp *dp_display = platform_get_drvdata(pdev); >>>> - struct dp_display_private *dp; >>>> - >>>> - dp = container_of(dp_display, struct dp_display_private, dp_display); >>>> - >>>> - mutex_lock(&dp->event_mutex); >>>> - >>>> - drm_dbg_dp(dp->drm_dev, >>>> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >>>> - dp->dp_display.connector_type, dp->core_initialized, >>>> - dp->phy_initialized, dp_display->power_on); >>>> - >>>> - /* mainlink enabled */ >>>> - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) >>>> - dp_ctrl_off_link_stream(dp->ctrl); >>>> - >>>> - dp_display_host_phy_exit(dp); >>> I was under the impression that dp_pm_runtime_suspend / _resume >>> functions perform phy init/exit only in eDP cases. Can we really drop >>> the main suspend/resume functions? >> yes on eDP case since it is embedded. > Let me ask the same question in a different way: > > dp_pm_suspend() / dp_pm_resume() functions contain several calls to DP > functions. Why can we drop them now? Maybe they had to be dropped in > one of the previous patches, when you have added proper runtime PM > support? > > Could you please confirm that after each patch the DP driver is > working, that there are no hidden dependencies between patches? patch #5 ==> drm/msm/dp: incorporate pm_runtime framework into DP driver patch #6 ==> drm/msm/dp: delete EV_HPD_INIT_SETUP patch #7 ==> drm/msm/dp: add pm_runtime_force_suspend()/resume() <== both dp_pm_suspend() and dp_pm_resume() are dropped here Patch #5 is this patch and dp_pm_suspend() and dp_pm_resume() still kept. patch #7 drop both dp_pm_suspend() and dp_pm_resume(). In order to keep every patch work for suspend/resume test, I drop dp_pm_susend() and dp_pm_resuem() at patch #7. yes, i confirm each patch DP driver is working. > >> for external DP case, there are two steps >> >> step 1: enable DP controller's hpd block and start waiting for hpd >> interrupts at dp_display_hpd_enable() The step number I mentioned here is for hpd_internal == true case. > Step 1 should be optional. DP should be functional even if the > .hpd_enable was not called. Have you tested this usecase? yes, for hpd_internal == false, step #1 is not required. however I do not have device to test it. But i think it should work since pm_runtime_resume_and_get() and pm_runtime_put_sync() to dp_hpd_plug_handle() and dp_hpd_unplug_handle() respectively. >> step 2: at plugin interrupts, dp_display_host_phy_init() >> >> step 3: at unplug interrupt: dp_bridge_atomic_post_disable() >> dp_display_host_phy_exi() >> >> at runtime, there is loop between step 2 and step 3 >> >> step 4: disable DP controller's hpd block >> >>>> - >>>> - /* host_init will be called at pm_resume */ >>>> - dp_display_host_deinit(dp); >>>> - >>>> - dp->hpd_state = ST_SUSPENDED; >>>> - >>>> - drm_dbg_dp(dp->drm_dev, >>>> - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >>>> - dp->dp_display.connector_type, dp->core_initialized, >>>> - dp->phy_initialized, dp_display->power_on); >>>> - >>>> - mutex_unlock(&dp->event_mutex); >>>> - >>>> - return 0; >>>> -} >>>> - >>>> static const struct dev_pm_ops dp_pm_ops = { >>>> SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) >>>> - .suspend = dp_pm_suspend, >>>> - .resume = dp_pm_resume, >>>> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, >>>> + pm_runtime_force_resume) >>>> }; >>>> >>>> static struct platform_driver dp_display_driver = { >>>> @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, >>>> >>>> dp_display = container_of(dp, struct dp_display_private, dp_display); >>>> >>>> - if (dp->is_edp) >>>> - dp_hpd_unplug_handle(dp_display, 0); >>> Why? >> dp_hpd_unplug_handle() does not tear down phy. >> >> Therefore eDP does not need to call unplug handle. > I don't fully understand your argument here. Could you please > describe, why this function call was necessary beforehand and what is > being changed now, so that it becomes unnecessary? dp_hpd_unplug_handle() is not necessary for eDP from very beginning since dp_bridge_atomic_enable() do it all (tear down link and phy). I think it was added long time ago mistakenly just like to be compatible with external DP since external DP always have dp_hpd_unplug_handle() called from irq_handle(). i can restore it back if you insist it. >> >> >>>> - >>>> mutex_lock(&dp_display->event_mutex); >>>> >>>> state = dp_display->hpd_state; >>>> @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) >>>> dp_catalog_ctrl_hpd_disable(dp->catalog); >>>> >>>> dp_display->internal_hpd = false; >>>> + dp->hpd_state = ST_DISCONNECTED; >>> Why? We have only disabled sending of the HPD events. The dongle might >>> still be connected. >> dp_bridge_hpd_disable() disable dp controller hpd block (no more hpd >> interrupt will be received). >> >> dp_bridge_hpd_disable() should happen after DP main link had been teared >> down already. > No, this assumption is incorrect. hpd_disable can happen at any point > during runtime. > It merely disables HPD interrupt generation, it has nothing to do with > the DP block being enabled or not. > >> Therefore hpd_state need to be in default state so that next plugin >> handle will be start with correct state. >> >> >>>> pm_runtime_mark_last_busy(&dp->pdev->dev); >>>> pm_runtime_put_autosuspend(&dp->pdev->dev); >>>> -- >>>> 2.7.4 >>>> >>> -- >>> With best wishes >>> >>> Dmitry > >
On Wed, 4 Oct 2023 at 01:12, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: > > > On 10/3/2023 10:53 AM, Dmitry Baryshkov wrote: > > On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: > >> > >> On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote: > >>> On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: > >>>> After incorporated pm_runtime framework into eDP/DP driver, the > >>> incorporating > >>> > >>> > >>>> original dp_pm_suspend() to handle power off both DP phy and > >>>> controller during suspend and dp_pm_resume() to handle power on > >>>> both DP phy and controller during resume are not necessary since > >>>> those function are replaced by dp_pm_runtime_suspend() and > >>>> dp_pm_runtime_resume() through pm runtime framework. > >>>> Therefore add pm framework provides functions, > >>>> pm_runtime_force_suspend()/resume() to complete incorporating pm > >>>> runtime framework into DP driver. > >>>> > >>>> Changes in v4: > >>>> -- drop both dp_pm_prepare() and dp_pm_compete() from this change > >>>> -- delete ST_SUSPENDED state > >>>> -- rewording commit text to add more details regrading the purpose > >>>> of this change > >>>> > >>>> Changes in v3: > >>>> -- replace dp_pm_suspend() with pm_runtime_force_suspend() > >>>> -- replace dp_pm_resume() with pm_runtime_force_resume() > >>>> > >>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> > >>>> --- > >>>> drivers/gpu/drm/msm/dp/dp_display.c | 113 ++---------------------------------- > >>>> 1 file changed, 5 insertions(+), 108 deletions(-) > >>>> > >>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c > >>>> index 9158a2c..711d262 100644 > >>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c > >>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c > >>>> @@ -49,7 +49,6 @@ enum { > >>>> ST_CONNECTED, > >>>> ST_DISCONNECT_PENDING, > >>>> ST_DISPLAY_OFF, > >>>> - ST_SUSPENDED, > >>>> }; > >>>> > >>>> enum { > >>>> @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) > >>>> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", > >>>> dp->dp_display.connector_type, state); > >>>> > >>>> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { > >>>> + if (state == ST_DISPLAY_OFF) { > >>>> mutex_unlock(&dp->event_mutex); > >>>> return 0; > >>>> } > >>>> @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) > >>>> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", > >>>> dp->dp_display.connector_type, state); > >>>> > >>>> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { > >>>> + if (state == ST_DISPLAY_OFF) { > >>>> mutex_unlock(&dp->event_mutex); > >>>> return 0; > >>>> } > >>>> @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) > >>>> return 0; > >>>> } > >>>> > >>>> -static int dp_pm_resume(struct device *dev) > >>>> -{ > >>>> - struct platform_device *pdev = to_platform_device(dev); > >>>> - struct msm_dp *dp_display = platform_get_drvdata(pdev); > >>>> - struct dp_display_private *dp; > >>>> - int sink_count = 0; > >>>> - > >>>> - dp = container_of(dp_display, struct dp_display_private, dp_display); > >>>> - > >>>> - mutex_lock(&dp->event_mutex); > >>>> - > >>>> - drm_dbg_dp(dp->drm_dev, > >>>> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > >>>> - dp->dp_display.connector_type, dp->core_initialized, > >>>> - dp->phy_initialized, dp_display->power_on); > >>>> - > >>>> - /* start from disconnected state */ > >>>> - dp->hpd_state = ST_DISCONNECTED; > >>>> - > >>>> - /* turn on dp ctrl/phy */ > >>>> - dp_display_host_init(dp); > >>>> - > >>>> - if (dp_display->is_edp) > >>>> - dp_catalog_ctrl_hpd_enable(dp->catalog); > >>>> - > >>>> - 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); > >>>> - } > >>>> - > >>>> - dp->link->sink_count = sink_count; > >>>> - /* > >>>> - * can not declared display is connected unless > >>>> - * HDMI cable is plugged in and sink_count of > >>>> - * dongle become 1 > >>>> - * also only signal audio when disconnected > >>>> - */ > >>>> - if (dp->link->sink_count) { > >>>> - dp->dp_display.link_ready = true; > >>>> - } else { > >>>> - dp->dp_display.link_ready = false; > >>>> - dp_display_handle_plugged_change(dp_display, false); > >>>> - } > >>>> - > >>>> - drm_dbg_dp(dp->drm_dev, > >>>> - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", > >>>> - dp->dp_display.connector_type, dp->link->sink_count, > >>>> - dp->dp_display.link_ready, dp->core_initialized, > >>>> - dp->phy_initialized, dp_display->power_on); > >>>> - > >>>> - mutex_unlock(&dp->event_mutex); > >>>> - > >>>> - return 0; > >>>> -} > >>>> - > >>>> -static int dp_pm_suspend(struct device *dev) > >>>> -{ > >>>> - struct platform_device *pdev = to_platform_device(dev); > >>>> - struct msm_dp *dp_display = platform_get_drvdata(pdev); > >>>> - struct dp_display_private *dp; > >>>> - > >>>> - dp = container_of(dp_display, struct dp_display_private, dp_display); > >>>> - > >>>> - mutex_lock(&dp->event_mutex); > >>>> - > >>>> - drm_dbg_dp(dp->drm_dev, > >>>> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > >>>> - dp->dp_display.connector_type, dp->core_initialized, > >>>> - dp->phy_initialized, dp_display->power_on); > >>>> - > >>>> - /* mainlink enabled */ > >>>> - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) > >>>> - dp_ctrl_off_link_stream(dp->ctrl); > >>>> - > >>>> - dp_display_host_phy_exit(dp); > >>> I was under the impression that dp_pm_runtime_suspend / _resume > >>> functions perform phy init/exit only in eDP cases. Can we really drop > >>> the main suspend/resume functions? > >> yes on eDP case since it is embedded. > > Let me ask the same question in a different way: > > > > dp_pm_suspend() / dp_pm_resume() functions contain several calls to DP > > functions. Why can we drop them now? Maybe they had to be dropped in > > one of the previous patches, when you have added proper runtime PM > > support? > > > > Could you please confirm that after each patch the DP driver is > > working, that there are no hidden dependencies between patches? > > patch #5 ==> drm/msm/dp: incorporate pm_runtime framework into DP driver > > patch #6 ==> drm/msm/dp: delete EV_HPD_INIT_SETUP > > patch #7 ==> drm/msm/dp: add pm_runtime_force_suspend()/resume() <== > both dp_pm_suspend() and dp_pm_resume() are dropped here > > > Patch #5 is this patch and dp_pm_suspend() and dp_pm_resume() still kept. > > patch #7 drop both dp_pm_suspend() and dp_pm_resume(). This makes me wonder if squashing #5 and #7 would have resulted in a cleaner and easier to understand patch. This way we'd be able to observer code moved from suspend/resume to runtime_suspend / runtime_resume > > In order to keep every patch work for suspend/resume test, I drop > dp_pm_susend() and dp_pm_resuem() at patch #7. > > yes, i confirm each patch DP driver is working. Ack, thank you. > > > > > >> for external DP case, there are two steps > >> > >> step 1: enable DP controller's hpd block and start waiting for hpd > >> interrupts at dp_display_hpd_enable() > The step number I mentioned here is for hpd_internal == true case. > > Step 1 should be optional. DP should be functional even if the > > .hpd_enable was not called. Have you tested this usecase? > > yes, for hpd_internal == false, step #1 is not required. > > however I do not have device to test it. You have. Just add a dp-connector with hpd-gpios to any of your DP-enabled devices and change the pinctrl for hpd pin to use the gpio function instead of HPD. > > But i think it should work since pm_runtime_resume_and_get() and > pm_runtime_put_sync() to dp_hpd_plug_handle() and dp_hpd_unplug_handle() > respectively. Ack. > >> step 2: at plugin interrupts, dp_display_host_phy_init() > >> > >> step 3: at unplug interrupt: dp_bridge_atomic_post_disable() > >> dp_display_host_phy_exi() > >> > >> at runtime, there is loop between step 2 and step 3 > >> > >> step 4: disable DP controller's hpd block > >> > >>>> - > >>>> - /* host_init will be called at pm_resume */ > >>>> - dp_display_host_deinit(dp); > >>>> - > >>>> - dp->hpd_state = ST_SUSPENDED; > >>>> - > >>>> - drm_dbg_dp(dp->drm_dev, > >>>> - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", > >>>> - dp->dp_display.connector_type, dp->core_initialized, > >>>> - dp->phy_initialized, dp_display->power_on); > >>>> - > >>>> - mutex_unlock(&dp->event_mutex); > >>>> - > >>>> - return 0; > >>>> -} > >>>> - > >>>> static const struct dev_pm_ops dp_pm_ops = { > >>>> SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) > >>>> - .suspend = dp_pm_suspend, > >>>> - .resume = dp_pm_resume, > >>>> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, > >>>> + pm_runtime_force_resume) > >>>> }; > >>>> > >>>> static struct platform_driver dp_display_driver = { > >>>> @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, > >>>> > >>>> dp_display = container_of(dp, struct dp_display_private, dp_display); > >>>> > >>>> - if (dp->is_edp) > >>>> - dp_hpd_unplug_handle(dp_display, 0); > >>> Why? > >> dp_hpd_unplug_handle() does not tear down phy. > >> > >> Therefore eDP does not need to call unplug handle. > > I don't fully understand your argument here. Could you please > > describe, why this function call was necessary beforehand and what is > > being changed now, so that it becomes unnecessary? > > dp_hpd_unplug_handle() is not necessary for eDP from very beginning > since dp_bridge_atomic_enable() do it all (tear down link and phy). Excuse me? Where does dp_bridge_atomic_enable() tear down the link? > > I think it was added long time ago mistakenly just like to be > compatible with external DP since external DP always have > dp_hpd_unplug_handle() called from irq_handle(). > > i can restore it back if you insist it. I insist on having clean documented patches. If function call was not necessary beforehand, please drop it in the separate patch with proper description of why and what. > > > >> > >> > >>>> - > >>>> mutex_lock(&dp_display->event_mutex); > >>>> > >>>> state = dp_display->hpd_state; > >>>> @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) > >>>> dp_catalog_ctrl_hpd_disable(dp->catalog); > >>>> > >>>> dp_display->internal_hpd = false; > >>>> + dp->hpd_state = ST_DISCONNECTED; > >>> Why? We have only disabled sending of the HPD events. The dongle might > >>> still be connected. > >> dp_bridge_hpd_disable() disable dp controller hpd block (no more hpd > >> interrupt will be received). > >> > >> dp_bridge_hpd_disable() should happen after DP main link had been teared > >> down already. > > No, this assumption is incorrect. hpd_disable can happen at any point > > during runtime. > > It merely disables HPD interrupt generation, it has nothing to do with > > the DP block being enabled or not. > > > >> Therefore hpd_state need to be in default state so that next plugin > >> handle will be start with correct state. > >> > >> > >>>> pm_runtime_mark_last_busy(&dp->pdev->dev); > >>>> pm_runtime_put_autosuspend(&dp->pdev->dev); > >>>> -- > >>>> 2.7.4 > >>>> > >>> -- > >>> With best wishes > >>> > >>> Dmitry > > > >
On 10/3/2023 3:36 PM, Dmitry Baryshkov wrote: > On Wed, 4 Oct 2023 at 01:12, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: >> >> On 10/3/2023 10:53 AM, Dmitry Baryshkov wrote: >>> On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: >>>> On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote: >>>>> On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote: >>>>>> After incorporated pm_runtime framework into eDP/DP driver, the >>>>> incorporating >>>>> >>>>> >>>>>> original dp_pm_suspend() to handle power off both DP phy and >>>>>> controller during suspend and dp_pm_resume() to handle power on >>>>>> both DP phy and controller during resume are not necessary since >>>>>> those function are replaced by dp_pm_runtime_suspend() and >>>>>> dp_pm_runtime_resume() through pm runtime framework. >>>>>> Therefore add pm framework provides functions, >>>>>> pm_runtime_force_suspend()/resume() to complete incorporating pm >>>>>> runtime framework into DP driver. >>>>>> >>>>>> Changes in v4: >>>>>> -- drop both dp_pm_prepare() and dp_pm_compete() from this change >>>>>> -- delete ST_SUSPENDED state >>>>>> -- rewording commit text to add more details regrading the purpose >>>>>> of this change >>>>>> >>>>>> Changes in v3: >>>>>> -- replace dp_pm_suspend() with pm_runtime_force_suspend() >>>>>> -- replace dp_pm_resume() with pm_runtime_force_resume() >>>>>> >>>>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> >>>>>> --- >>>>>> drivers/gpu/drm/msm/dp/dp_display.c | 113 ++---------------------------------- >>>>>> 1 file changed, 5 insertions(+), 108 deletions(-) >>>>>> >>>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c >>>>>> index 9158a2c..711d262 100644 >>>>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c >>>>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c >>>>>> @@ -49,7 +49,6 @@ enum { >>>>>> ST_CONNECTED, >>>>>> ST_DISCONNECT_PENDING, >>>>>> ST_DISPLAY_OFF, >>>>>> - ST_SUSPENDED, >>>>>> }; >>>>>> >>>>>> enum { >>>>>> @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) >>>>>> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", >>>>>> dp->dp_display.connector_type, state); >>>>>> >>>>>> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { >>>>>> + if (state == ST_DISPLAY_OFF) { >>>>>> mutex_unlock(&dp->event_mutex); >>>>>> return 0; >>>>>> } >>>>>> @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) >>>>>> drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", >>>>>> dp->dp_display.connector_type, state); >>>>>> >>>>>> - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { >>>>>> + if (state == ST_DISPLAY_OFF) { >>>>>> mutex_unlock(&dp->event_mutex); >>>>>> return 0; >>>>>> } >>>>>> @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) >>>>>> return 0; >>>>>> } >>>>>> >>>>>> -static int dp_pm_resume(struct device *dev) >>>>>> -{ >>>>>> - struct platform_device *pdev = to_platform_device(dev); >>>>>> - struct msm_dp *dp_display = platform_get_drvdata(pdev); >>>>>> - struct dp_display_private *dp; >>>>>> - int sink_count = 0; >>>>>> - >>>>>> - dp = container_of(dp_display, struct dp_display_private, dp_display); >>>>>> - >>>>>> - mutex_lock(&dp->event_mutex); >>>>>> - >>>>>> - drm_dbg_dp(dp->drm_dev, >>>>>> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >>>>>> - dp->dp_display.connector_type, dp->core_initialized, >>>>>> - dp->phy_initialized, dp_display->power_on); >>>>>> - >>>>>> - /* start from disconnected state */ >>>>>> - dp->hpd_state = ST_DISCONNECTED; >>>>>> - >>>>>> - /* turn on dp ctrl/phy */ >>>>>> - dp_display_host_init(dp); >>>>>> - >>>>>> - if (dp_display->is_edp) >>>>>> - dp_catalog_ctrl_hpd_enable(dp->catalog); >>>>>> - >>>>>> - 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); >>>>>> - } >>>>>> - >>>>>> - dp->link->sink_count = sink_count; >>>>>> - /* >>>>>> - * can not declared display is connected unless >>>>>> - * HDMI cable is plugged in and sink_count of >>>>>> - * dongle become 1 >>>>>> - * also only signal audio when disconnected >>>>>> - */ >>>>>> - if (dp->link->sink_count) { >>>>>> - dp->dp_display.link_ready = true; >>>>>> - } else { >>>>>> - dp->dp_display.link_ready = false; >>>>>> - dp_display_handle_plugged_change(dp_display, false); >>>>>> - } >>>>>> - >>>>>> - drm_dbg_dp(dp->drm_dev, >>>>>> - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", >>>>>> - dp->dp_display.connector_type, dp->link->sink_count, >>>>>> - dp->dp_display.link_ready, dp->core_initialized, >>>>>> - dp->phy_initialized, dp_display->power_on); >>>>>> - >>>>>> - mutex_unlock(&dp->event_mutex); >>>>>> - >>>>>> - return 0; >>>>>> -} >>>>>> - >>>>>> -static int dp_pm_suspend(struct device *dev) >>>>>> -{ >>>>>> - struct platform_device *pdev = to_platform_device(dev); >>>>>> - struct msm_dp *dp_display = platform_get_drvdata(pdev); >>>>>> - struct dp_display_private *dp; >>>>>> - >>>>>> - dp = container_of(dp_display, struct dp_display_private, dp_display); >>>>>> - >>>>>> - mutex_lock(&dp->event_mutex); >>>>>> - >>>>>> - drm_dbg_dp(dp->drm_dev, >>>>>> - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >>>>>> - dp->dp_display.connector_type, dp->core_initialized, >>>>>> - dp->phy_initialized, dp_display->power_on); >>>>>> - >>>>>> - /* mainlink enabled */ >>>>>> - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) >>>>>> - dp_ctrl_off_link_stream(dp->ctrl); >>>>>> - >>>>>> - dp_display_host_phy_exit(dp); >>>>> I was under the impression that dp_pm_runtime_suspend / _resume >>>>> functions perform phy init/exit only in eDP cases. Can we really drop >>>>> the main suspend/resume functions? >>>> yes on eDP case since it is embedded. >>> Let me ask the same question in a different way: >>> >>> dp_pm_suspend() / dp_pm_resume() functions contain several calls to DP >>> functions. Why can we drop them now? Maybe they had to be dropped in >>> one of the previous patches, when you have added proper runtime PM >>> support? >>> >>> Could you please confirm that after each patch the DP driver is >>> working, that there are no hidden dependencies between patches? >> patch #5 ==> drm/msm/dp: incorporate pm_runtime framework into DP driver >> >> patch #6 ==> drm/msm/dp: delete EV_HPD_INIT_SETUP >> >> patch #7 ==> drm/msm/dp: add pm_runtime_force_suspend()/resume() <== >> both dp_pm_suspend() and dp_pm_resume() are dropped here >> >> >> Patch #5 is this patch and dp_pm_suspend() and dp_pm_resume() still kept. >> >> patch #7 drop both dp_pm_suspend() and dp_pm_resume(). > This makes me wonder if squashing #5 and #7 would have resulted in a > cleaner and easier to understand patch. This way we'd be able to > observer code moved from suspend/resume to runtime_suspend / > runtime_resume ok, i will merge both two patches together >> In order to keep every patch work for suspend/resume test, I drop >> dp_pm_susend() and dp_pm_resuem() at patch #7. >> >> yes, i confirm each patch DP driver is working. > Ack, thank you. > >> >>>> for external DP case, there are two steps >>>> >>>> step 1: enable DP controller's hpd block and start waiting for hpd >>>> interrupts at dp_display_hpd_enable() >> The step number I mentioned here is for hpd_internal == true case. >>> Step 1 should be optional. DP should be functional even if the >>> .hpd_enable was not called. Have you tested this usecase? >> yes, for hpd_internal == false, step #1 is not required. >> >> however I do not have device to test it. > You have. Just add a dp-connector with hpd-gpios to any of your > DP-enabled devices and change the pinctrl for hpd pin to use the gpio > function instead of HPD. > >> But i think it should work since pm_runtime_resume_and_get() and >> pm_runtime_put_sync() to dp_hpd_plug_handle() and dp_hpd_unplug_handle() >> respectively. > Ack. > > >>>> step 2: at plugin interrupts, dp_display_host_phy_init() >>>> >>>> step 3: at unplug interrupt: dp_bridge_atomic_post_disable() >>>> dp_display_host_phy_exi() >>>> >>>> at runtime, there is loop between step 2 and step 3 >>>> >>>> step 4: disable DP controller's hpd block >>>> >>>>>> - >>>>>> - /* host_init will be called at pm_resume */ >>>>>> - dp_display_host_deinit(dp); >>>>>> - >>>>>> - dp->hpd_state = ST_SUSPENDED; >>>>>> - >>>>>> - drm_dbg_dp(dp->drm_dev, >>>>>> - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", >>>>>> - dp->dp_display.connector_type, dp->core_initialized, >>>>>> - dp->phy_initialized, dp_display->power_on); >>>>>> - >>>>>> - mutex_unlock(&dp->event_mutex); >>>>>> - >>>>>> - return 0; >>>>>> -} >>>>>> - >>>>>> static const struct dev_pm_ops dp_pm_ops = { >>>>>> SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) >>>>>> - .suspend = dp_pm_suspend, >>>>>> - .resume = dp_pm_resume, >>>>>> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, >>>>>> + pm_runtime_force_resume) >>>>>> }; >>>>>> >>>>>> static struct platform_driver dp_display_driver = { >>>>>> @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, >>>>>> >>>>>> dp_display = container_of(dp, struct dp_display_private, dp_display); >>>>>> >>>>>> - if (dp->is_edp) >>>>>> - dp_hpd_unplug_handle(dp_display, 0); >>>>> Why? >>>> dp_hpd_unplug_handle() does not tear down phy. >>>> >>>> Therefore eDP does not need to call unplug handle. >>> I don't fully understand your argument here. Could you please >>> describe, why this function call was necessary beforehand and what is >>> being changed now, so that it becomes unnecessary? >> dp_hpd_unplug_handle() is not necessary for eDP from very beginning >> since dp_bridge_atomic_enable() do it all (tear down link and phy). > Excuse me? Where does dp_bridge_atomic_enable() tear down the link? my bad, it is dp_bridge_atomic_post_disable() > >> I think it was added long time ago mistakenly just like to be >> compatible with external DP since external DP always have >> dp_hpd_unplug_handle() called from irq_handle(). >> >> i can restore it back if you insist it. > I insist on having clean documented patches. If function call was not > necessary beforehand, please drop it in the separate patch with proper > description of why and what. > ok, will restore it back. >> >>>> >>>>>> - >>>>>> mutex_lock(&dp_display->event_mutex); >>>>>> >>>>>> state = dp_display->hpd_state; >>>>>> @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) >>>>>> dp_catalog_ctrl_hpd_disable(dp->catalog); >>>>>> >>>>>> dp_display->internal_hpd = false; >>>>>> + dp->hpd_state = ST_DISCONNECTED; >>>>> Why? We have only disabled sending of the HPD events. The dongle might >>>>> still be connected. >>>> dp_bridge_hpd_disable() disable dp controller hpd block (no more hpd >>>> interrupt will be received). >>>> >>>> dp_bridge_hpd_disable() should happen after DP main link had been teared >>>> down already. >>> No, this assumption is incorrect. hpd_disable can happen at any point >>> during runtime. >>> It merely disables HPD interrupt generation, it has nothing to do with >>> the DP block being enabled or not. >>> >>>> Therefore hpd_state need to be in default state so that next plugin >>>> handle will be start with correct state. >>>> >>>> >>>>>> pm_runtime_mark_last_busy(&dp->pdev->dev); >>>>>> pm_runtime_put_autosuspend(&dp->pdev->dev); >>>>>> -- >>>>>> 2.7.4 >>>>>> >>>>> -- >>>>> With best wishes >>>>> >>>>> Dmitry >>> > >
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 9158a2c..711d262 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -49,7 +49,6 @@ enum { ST_CONNECTED, ST_DISCONNECT_PENDING, ST_DISPLAY_OFF, - ST_SUSPENDED, }; enum { @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev) return 0; } -static int dp_pm_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct msm_dp *dp_display = platform_get_drvdata(pdev); - struct dp_display_private *dp; - int sink_count = 0; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->event_mutex); - - drm_dbg_dp(dp->drm_dev, - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - /* start from disconnected state */ - dp->hpd_state = ST_DISCONNECTED; - - /* turn on dp ctrl/phy */ - dp_display_host_init(dp); - - if (dp_display->is_edp) - dp_catalog_ctrl_hpd_enable(dp->catalog); - - 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); - } - - dp->link->sink_count = sink_count; - /* - * can not declared display is connected unless - * HDMI cable is plugged in and sink_count of - * dongle become 1 - * also only signal audio when disconnected - */ - if (dp->link->sink_count) { - dp->dp_display.link_ready = true; - } else { - dp->dp_display.link_ready = false; - dp_display_handle_plugged_change(dp_display, false); - } - - drm_dbg_dp(dp->drm_dev, - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", - dp->dp_display.connector_type, dp->link->sink_count, - dp->dp_display.link_ready, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - mutex_unlock(&dp->event_mutex); - - return 0; -} - -static int dp_pm_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct msm_dp *dp_display = platform_get_drvdata(pdev); - struct dp_display_private *dp; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->event_mutex); - - drm_dbg_dp(dp->drm_dev, - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - /* mainlink enabled */ - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) - dp_ctrl_off_link_stream(dp->ctrl); - - dp_display_host_phy_exit(dp); - - /* host_init will be called at pm_resume */ - dp_display_host_deinit(dp); - - dp->hpd_state = ST_SUSPENDED; - - drm_dbg_dp(dp->drm_dev, - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - mutex_unlock(&dp->event_mutex); - - return 0; -} - static const struct dev_pm_ops dp_pm_ops = { SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) - .suspend = dp_pm_suspend, - .resume = dp_pm_resume, + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver dp_display_driver = { @@ -1658,9 +1557,6 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, dp_display = container_of(dp, struct dp_display_private, dp_display); - if (dp->is_edp) - dp_hpd_unplug_handle(dp_display, 0); - mutex_lock(&dp_display->event_mutex); state = dp_display->hpd_state; @@ -1748,6 +1644,7 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) dp_catalog_ctrl_hpd_disable(dp->catalog); dp_display->internal_hpd = false; + dp->hpd_state = ST_DISCONNECTED; pm_runtime_mark_last_busy(&dp->pdev->dev); pm_runtime_put_autosuspend(&dp->pdev->dev);