From patchwork Tue Apr 5 18:17:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 12802104 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C423EC433FE for ; Tue, 5 Apr 2022 23:34:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1457677AbiDEXHS (ORCPT ); Tue, 5 Apr 2022 19:07:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39938 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1573209AbiDESTT (ORCPT ); Tue, 5 Apr 2022 14:19:19 -0400 Received: from alexa-out.qualcomm.com (alexa-out.qualcomm.com [129.46.98.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9EC7CEF087; Tue, 5 Apr 2022 11:17:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1649182639; x=1680718639; h=from:to:cc:subject:date:message-id:mime-version; bh=bwqwyzqwG2MNZKE8hl5seyqxC+Y62bblO4gxfvbXvAY=; b=c0yBI+SGBSPZ+KLRNvlpTjPT3mRAO2yJuOtYt9AYWbkBANAcBnw3b7ZF jSuX9aTIEB51bizB41sh1Rykjyq5EUYdaBFqbGZJnfdjtNRnZP5zgmuEx tjFkqEo4wyFzw6qKjQ4syDMeTh63b6bb/1GvdgO2FYyQAuU3wuiV6wEft w=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 05 Apr 2022 11:17:19 -0700 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Apr 2022 11:17:19 -0700 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.22; Tue, 5 Apr 2022 11:17:18 -0700 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.986.22; Tue, 5 Apr 2022 11:17:17 -0700 From: Kuogee Hsieh To: , , , , , , , , CC: , , , , , , , Subject: [PATCH] drm/msm/dp: enhance both connect and disconnect pending_timeout handle Date: Tue, 5 Apr 2022 11:17:07 -0700 Message-ID: <1649182627-8068-1-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org HPD plugin handle is responsible for setting up main link and depend on user space frame work to start video stream. Similarly, HPD unplugged handle is responsible for tearing down main link and depend on user space frame work to stop video stream. Connect_pending_timeout and disconnect_ pending_timeout are fired after 5 seconds timer expired to tear down main link and video stream and restore DP driver state into known default DISCONNECTED state in the case of frame work does not response uevent original from DP driver so that DP driver can recover gracefully. The original connect_pending_timeout and disconnect_pending_timeout were not implemented correctly. This patch enhance both timeout functions to tear down main link and video stream correctly once timer is fired. Fixes: 8ede2ecc3e5e ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets") Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 34 ++++++++++++++++++++++++-- drivers/gpu/drm/msm/dp/dp_ctrl.h | 1 + drivers/gpu/drm/msm/dp/dp_display.c | 48 +++++++++++++++++++++++++++---------- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index dcd0126..3f4cf6d 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1910,7 +1910,7 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) return ret; } -int dp_ctrl_off(struct dp_ctrl *dp_ctrl) +int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; struct dp_io *dp_io; @@ -1926,7 +1926,37 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl) dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); - dp_catalog_ctrl_reset(ctrl->catalog); + ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + if (ret) { + DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); + } + + DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n", + (u32)(uintptr_t)phy, phy->init_count, phy->power_count); + + phy_power_off(phy); + + DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n", + (u32)(uintptr_t)phy, phy->init_count, phy->power_count); + + return ret; +} + +int dp_ctrl_off(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + struct dp_io *dp_io; + struct phy *phy; + int ret = 0; + + if (!dp_ctrl) + return -EINVAL; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + dp_io = &ctrl->parser->io; + phy = dp_io->phy; + + dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, false); if (ret) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index 2433edb..ffafe17 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -22,6 +22,7 @@ struct dp_ctrl { int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl); int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl); int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl); +int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl); int dp_ctrl_off(struct dp_ctrl *dp_ctrl); void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl); void dp_ctrl_isr(struct dp_ctrl *dp_ctrl); diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 178b774..56bf7c5 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -593,10 +593,16 @@ static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); + /* + * main link had been setup but video is not ready yet + * only tear down main link + */ state = dp->hpd_state; if (state == ST_CONNECT_PENDING) { - dp->hpd_state = ST_CONNECTED; DRM_DEBUG_DP("type=%d\n", dp->dp_display.connector_type); + dp_ctrl_off_link(dp->ctrl); + dp_display_host_phy_exit(dp); + dp->hpd_state = ST_DISCONNECTED; } mutex_unlock(&dp->event_mutex); @@ -645,6 +651,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) if (dp->link->sink_count == 0) { dp_display_host_phy_exit(dp); } + dp_display_usbpd_disconnect_cb(&dp->pdev->dev); mutex_unlock(&dp->event_mutex); return 0; } @@ -661,19 +668,19 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) return 0; } - dp->hpd_state = ST_DISCONNECT_PENDING; - /* disable HPD plug interrupts */ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); - /* - * We don't need separate work for disconnect as - * connect/attention interrupts are disabled - */ dp_display_usbpd_disconnect_cb(&dp->pdev->dev); - /* start sentinel checking in case of missing uevent */ - dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); + if (state == ST_DISPLAY_OFF) { + dp->hpd_state = ST_DISCONNECTED; + + } else { + /* start sentinel checking in case of missing uevent */ + dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); + dp->hpd_state = ST_DISCONNECT_PENDING; + } /* signal the disconnect event early to ensure proper teardown */ dp_display_handle_plugged_change(&dp->dp_display, false); @@ -695,10 +702,16 @@ static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data mutex_lock(&dp->event_mutex); + /* + * main link had been set up and video is ready + * tear down main link, video stream and phy + */ state = dp->hpd_state; if (state == ST_DISCONNECT_PENDING) { - dp->hpd_state = ST_DISCONNECTED; DRM_DEBUG_DP("type=%d\n", dp->dp_display.connector_type); + dp_ctrl_off(dp->ctrl); + dp_display_host_phy_exit(dp); + dp->hpd_state = ST_DISCONNECTED; } mutex_unlock(&dp->event_mutex); @@ -1571,6 +1584,12 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder) mutex_lock(&dp_display->event_mutex); + state = dp_display->hpd_state; + if (state == ST_DISCONNECTED) { + mutex_unlock(&dp_display->event_mutex); + return rc; + } + /* stop sentinel checking */ dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT); @@ -1588,8 +1607,6 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder) return rc; } - state = dp_display->hpd_state; - if (state == ST_DISPLAY_OFF) dp_display_host_phy_init(dp_display); @@ -1638,13 +1655,18 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) /* stop sentinel checking */ dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT); + state = dp_display->hpd_state; + if (state == ST_DISCONNECTED || state == ST_DISPLAY_OFF) { + mutex_unlock(&dp_display->event_mutex); + return rc; + } + dp_display_disable(dp_display, 0); rc = dp_display_unprepare(dp); if (rc) DRM_ERROR("DP display unprepare failed, rc=%d\n", rc); - state = dp_display->hpd_state; if (state == ST_DISCONNECT_PENDING) { /* completed disconnection */ dp_display->hpd_state = ST_DISCONNECTED;