From patchwork Thu Feb 23 13:56:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sankeerth Billakanti (QUIC)" X-Patchwork-Id: 13150457 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 gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2329BC636D6 for ; Thu, 23 Feb 2023 13:57:21 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 00CCF10EB89; Thu, 23 Feb 2023 13:57:20 +0000 (UTC) Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9888010EB89; Thu, 23 Feb 2023 13:57:17 +0000 (UTC) Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 31NB5IvO016391; Thu, 23 Feb 2023 13:57:14 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-transfer-encoding : content-type; s=qcppdkim1; bh=l8TV4wziODhnWMNfw51Yr1Ob/oEB18/ZBAhON/fJ9/o=; b=hYWmX5KvseEOkyNv/snqVaqd6YneAhGD/A7bnEj8Kv0L6Db3PsnTegxLQXAHTU9ELxwY zBK+IsYQ4EoICwza6GncJh8cH2Z/1e6xW9jHMwIIgS7MNJbvePxwtZXxW+rRkWQlSWR5 wY61X7PbHa8jq3HHxmnc0ERLjIEgjUuo5iVRxU9X6iyZRNUqIZU4+0BqotpYcn48DC1/ Yt79DXH4tFrUNLtkdNj+ZgYnA4ALpkIrSs1Jsw8aVDpG0hwHxv79EwcPuX50x1XL9gUQ l6NxGx77r8PNzmluG7UksTRZDZTqZxBvdRSBqLvJNP39hqgujltHGTUcJy//Zfgwc2Ue BQ== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3nwyc5hhax-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 23 Feb 2023 13:57:14 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 31NDvD13031304 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 23 Feb 2023 13:57:13 GMT Received: from sbillaka-linux.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.41; Thu, 23 Feb 2023 05:57:07 -0800 From: Sankeerth Billakanti To: , , , Subject: [RFC PATCH 1/2] drm/msm/dp: enumerate edp panel during driver probe Date: Thu, 23 Feb 2023 19:26:34 +0530 Message-ID: <20230223135635.30659-2-quic_sbillaka@quicinc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230223135635.30659-1-quic_sbillaka@quicinc.com> References: <20230223135635.30659-1-quic_sbillaka@quicinc.com> MIME-Version: 1.0 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: HX9OIdFG-Im8kzouc5ZoKZuS9ygLzk_8 X-Proofpoint-GUID: HX9OIdFG-Im8kzouc5ZoKZuS9ygLzk_8 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.170.22 definitions=2023-02-23_08,2023-02-23_01,2023-02-09_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 suspectscore=0 phishscore=0 spamscore=0 mlxlogscore=999 bulkscore=0 adultscore=0 mlxscore=0 priorityscore=1501 lowpriorityscore=0 impostorscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2302230114 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: quic_kalyant@quicinc.com, Sankeerth Billakanti , dianders@chromium.org, quic_bjorande@quicinc.com, quic_vproddut@quicinc.com, airlied@linux.ie, quic_abhinavk@quicinc.com, swboyd@chromium.org, seanpaul@chromium.org, dmitry.baryshkov@linaro.org, quic_khsieh@quicinc.com, sean@poorly.run Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The eDP panel is identified and enumerated during probe of the panel-edp driver. The current DP driver triggers this panel-edp driver probe while getting the panel-bridge associated with the eDP panel from the platform driver bind. If the panel-edp probe is deferred, then the whole bunch of MDSS parent and child drivers have to defer and roll back. So, we want to move the panel enumeration from bind to probe so that the probe defer is easier to handle and also both the drivers appear consistent in panel enumeration. This change moves the DP driver panel-bridge enumeration to probe. Signed-off-by: Sankeerth Billakanti --- drivers/gpu/drm/msm/dp/dp_aux.c | 149 ++++++++++++++++++++++++++-- drivers/gpu/drm/msm/dp/dp_catalog.c | 12 +++ drivers/gpu/drm/msm/dp/dp_catalog.h | 1 + drivers/gpu/drm/msm/dp/dp_display.c | 80 ++++++--------- 4 files changed, 182 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index cc3efed593aa..5da95dfdeede 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -110,7 +110,7 @@ static ssize_t dp_aux_write(struct dp_aux_private *aux, } static ssize_t dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, - struct drm_dp_aux_msg *msg) + struct drm_dp_aux_msg *msg, bool poll) { ssize_t ret; unsigned long time_left; @@ -121,10 +121,16 @@ static ssize_t dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, if (ret < 0) return ret; - time_left = wait_for_completion_timeout(&aux->comp, + if (!poll) { + time_left = wait_for_completion_timeout(&aux->comp, msecs_to_jiffies(250)); - if (!time_left) - return -ETIMEDOUT; + if (!time_left) + return -ETIMEDOUT; + } else { + ret = dp_catalog_aux_poll_and_get_hw_interrupt(aux->catalog); + if (!ret) + dp_aux_isr(&aux->dp_aux); + } return ret; } @@ -238,7 +244,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, */ static void dp_aux_transfer_helper(struct dp_aux_private *aux, struct drm_dp_aux_msg *input_msg, - bool send_seg) + bool send_seg, bool poll) { struct drm_dp_aux_msg helper_msg; u32 message_size = 0x10; @@ -278,7 +284,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, helper_msg.address = segment_address; helper_msg.buffer = &aux->segment; helper_msg.size = 1; - dp_aux_cmd_fifo_tx(aux, &helper_msg); + dp_aux_cmd_fifo_tx(aux, &helper_msg, poll); } /* @@ -292,7 +298,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, helper_msg.address = input_msg->address; helper_msg.buffer = &aux->offset; helper_msg.size = 1; - dp_aux_cmd_fifo_tx(aux, &helper_msg); + dp_aux_cmd_fifo_tx(aux, &helper_msg, poll); end: aux->offset += message_size; @@ -300,6 +306,122 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, aux->segment = 0x0; /* reset segment at end of block */ } +/* + * This function does the real job to process an AUX transaction. + * It will call aux_reset() function to reset the AUX channel, + * if the waiting is timeout. + */ +static ssize_t dp_aux_transfer_init(struct drm_dp_aux *dp_aux, + struct drm_dp_aux_msg *msg) +{ + ssize_t ret; + int const aux_cmd_native_max = 16; + int const aux_cmd_i2c_max = 128; + struct dp_aux_private *aux; + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); + + /* Ignore address only message */ + if (msg->size == 0 || !msg->buffer) { + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + return msg->size; + } + + /* msg sanity check */ + if ((aux->native && msg->size > aux_cmd_native_max) || + msg->size > aux_cmd_i2c_max) { + DRM_ERROR("%s: invalid msg: size(%zu), request(%x)\n", + __func__, msg->size, msg->request); + return -EINVAL; + } + + mutex_lock(&aux->mutex); + if (!aux->initted) { + ret = -EIO; + goto exit; + } + + /* + * For eDP it's important to give a reasonably long wait here for HPD + * to be asserted. This is because the panel driver may have _just_ + * turned on the panel and then tried to do an AUX transfer. The panel + * driver has no way of knowing when the panel is ready, so it's up + * to us to wait. For DP we never get into this situation so let's + * avoid ever doing the extra long wait for DP. + */ + if (aux->is_edp) { + ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog); + if (ret) { + DRM_DEBUG_DP("Panel not ready for aux transactions\n"); + goto exit; + } + } + + dp_aux_update_offset_and_segment(aux, msg); + dp_aux_transfer_helper(aux, msg, true, true); + + aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + aux->cmd_busy = true; + + if (aux->read) { + aux->no_send_addr = true; + aux->no_send_stop = false; + } else { + aux->no_send_addr = true; + aux->no_send_stop = true; + } + + ret = dp_aux_cmd_fifo_tx(aux, msg, true); + + /* TODO: why is fifo_rx necessary here? + * Ideally fifo_rx need not be executed for an aux write + */ + ret = dp_aux_cmd_fifo_rx(aux, msg); + + if (ret < 0) { + if (aux->native) { + aux->retry_cnt++; + if (!(aux->retry_cnt % MAX_AUX_RETRIES)) + dp_catalog_aux_update_cfg(aux->catalog); + } + /* reset aux if link is in connected state */ + if (dp_catalog_link_is_connected(aux->catalog)) + dp_catalog_aux_reset(aux->catalog); + } else { + aux->retry_cnt = 0; + switch (aux->aux_error_num) { + case DP_AUX_ERR_NONE: + if (aux->read) + ret = dp_aux_cmd_fifo_rx(aux, msg); + msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + break; + case DP_AUX_ERR_DEFER: + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; + break; + case DP_AUX_ERR_PHY: + case DP_AUX_ERR_ADDR: + case DP_AUX_ERR_NACK: + case DP_AUX_ERR_NACK_DEFER: + msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_NACK : DP_AUX_I2C_REPLY_NACK; + break; + case DP_AUX_ERR_TOUT: + ret = -ETIMEDOUT; + break; + } + } + + aux->cmd_busy = false; + +exit: + mutex_unlock(&aux->mutex); + + return ret; +} + /* * This function does the real job to process an AUX transaction. * It will call aux_reset() function to reset the AUX channel, @@ -355,7 +477,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, } dp_aux_update_offset_and_segment(aux, msg); - dp_aux_transfer_helper(aux, msg, true); + dp_aux_transfer_helper(aux, msg, true, false); aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); aux->cmd_busy = true; @@ -368,7 +490,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, aux->no_send_stop = true; } - ret = dp_aux_cmd_fifo_tx(aux, msg); + ret = dp_aux_cmd_fifo_tx(aux, msg, false); if (ret < 0) { if (aux->native) { aux->retry_cnt++; @@ -535,6 +657,15 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, aux->catalog = catalog; aux->retry_cnt = 0; + /* + * Use the drm_dp_aux_init() to use the aux adapter + * before registering aux with the DRM device. + */ + aux->dp_aux.name = "dpu_dp_aux"; + aux->dp_aux.dev = dev; + aux->dp_aux.transfer = dp_aux_transfer_init; + drm_dp_aux_init(&aux->dp_aux); + return &aux->dp_aux; } diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 676279d0ca8d..ccf0400176f0 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -258,6 +258,18 @@ int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog) 2000, 500000); } +int dp_catalog_aux_poll_and_get_hw_interrupt(struct dp_catalog *dp_catalog) +{ + u32 aux; + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + return readl_poll_timeout(catalog->io->dp_controller.ahb.base + + REG_DP_INTR_STATUS, + aux, aux & DP_INTERRUPT_STATUS1, + 250, 250000); +} + static void dump_regs(void __iomem *base, int len) { int i; diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 1f717f45c115..ad4a9e0f71f2 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -87,6 +87,7 @@ void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable); void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog); int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog); u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog); +int dp_catalog_aux_poll_and_get_hw_interrupt(struct dp_catalog *dp_catalog); /* DP Controller APIs */ void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state); diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index bde1a7ce442f..a5dcef040b74 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -275,13 +275,6 @@ static int dp_display_bind(struct device *dev, struct device *master, dp->dp_display.drm_dev = drm; priv->dp[dp->id] = &dp->dp_display; - rc = dp->parser->parse(dp->parser); - if (rc) { - DRM_ERROR("device tree parsing failed\n"); - goto end; - } - - dp->drm_dev = drm; dp->aux->drm_dev = drm; rc = dp_aux_register(dp->aux); @@ -290,12 +283,6 @@ static int dp_display_bind(struct device *dev, struct device *master, goto end; } - rc = dp_power_client_init(dp->power); - if (rc) { - DRM_ERROR("Power client create failed\n"); - goto end; - } - rc = dp_register_audio_driver(dev, dp->audio); if (rc) { DRM_ERROR("Audio registration Dp failed\n"); @@ -787,6 +774,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error; } + rc = dp->parser->parse(dp->parser); + if (rc) { + DRM_ERROR("device tree parsing failed\n"); + goto error; + } + dp->catalog = dp_catalog_get(dev, &dp->parser->io); if (IS_ERR(dp->catalog)) { rc = PTR_ERR(dp->catalog); @@ -803,6 +796,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error; } + rc = dp_power_client_init(dp->power); + if (rc) { + DRM_ERROR("Power client create failed\n"); + goto error; + } + dp->aux = dp_aux_get(dev, dp->catalog, dp->dp_display.is_edp); if (IS_ERR(dp->aux)) { rc = PTR_ERR(dp->aux); @@ -1338,12 +1337,29 @@ static int dp_display_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &dp->dp_display); + if (dp->dp_display.is_edp) { + dp_display_host_init(dp); + dp_display_host_phy_init(dp); + dp_catalog_ctrl_hpd_config(dp->catalog); + + rc = devm_of_dp_aux_populate_bus(dp->aux, NULL); + + dp_display_host_phy_exit(dp); + dp_display_host_deinit(dp); + + if (rc) { + DRM_ERROR("failed to initialize panel, rc = %d\n", rc); + goto error; + } + } + rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { DRM_ERROR("component add failed, rc=%d\n", rc); dp_display_deinit_sub_modules(dp); } +error: return rc; } @@ -1546,40 +1562,8 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) { int rc; struct dp_display_private *dp_priv; - struct device_node *aux_bus; - struct device *dev; dp_priv = container_of(dp, struct dp_display_private, dp_display); - dev = &dp_priv->pdev->dev; - aux_bus = of_get_child_by_name(dev->of_node, "aux-bus"); - - if (aux_bus && dp->is_edp) { - dp_display_host_init(dp_priv); - dp_catalog_ctrl_hpd_config(dp_priv->catalog); - dp_display_host_phy_init(dp_priv); - enable_irq(dp_priv->irq); - - /* - * The code below assumes that the panel will finish probing - * by the time devm_of_dp_aux_populate_ep_devices() returns. - * This isn't a great assumption since it will fail if the - * panel driver is probed asynchronously but is the best we - * can do without a bigger driver reorganization. - */ - rc = of_dp_aux_populate_bus(dp_priv->aux, NULL); - of_node_put(aux_bus); - if (rc) - goto error; - - rc = devm_add_action_or_reset(dp->drm_dev->dev, - of_dp_aux_depopulate_bus_void, - dp_priv->aux); - if (rc) - goto error; - } else if (dp->is_edp) { - DRM_ERROR("eDP aux_bus not found\n"); - return -ENODEV; - } /* * External bridges are mandatory for eDP interfaces: one has to @@ -1597,12 +1581,6 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) return 0; } -error: - if (dp->is_edp) { - disable_irq(dp_priv->irq); - dp_display_host_phy_exit(dp_priv); - dp_display_host_deinit(dp_priv); - } return rc; } From patchwork Thu Feb 23 13:56:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sankeerth Billakanti (QUIC)" X-Patchwork-Id: 13150458 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 gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A228BC636D6 for ; Thu, 23 Feb 2023 13:57:29 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9F66210E4F7; Thu, 23 Feb 2023 13:57:28 +0000 (UTC) Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1B46810E4F7; Thu, 23 Feb 2023 13:57:26 +0000 (UTC) Received: from pps.filterd (m0279864.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 31NB4KSM007205; Thu, 23 Feb 2023 13:57:20 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-transfer-encoding : content-type; s=qcppdkim1; bh=7Cind5gyNxMy1Iej3zlc/j/6yrfUHAadhIOvgUWmRCI=; b=VYB0L1ZlutRnBHM/C7DdBlLIEHI3IkxkwG6AKxUufGnBa3bDfBJVgRjc1IbfCHKDqeaz ka6ITBRHBsBxpXDnNs7Rsho2uLjA64t3719WnD8Ti98TYIzrtDkGi1SUnpVrbt6gvhM3 i5dRAQkYUgJYmP3tvnvyq+B1+QgeroEFP6o0aJwCNAHn76qK2NYH5qgZ/i4iKhDhGNH3 BWGQ0JG49tIeNXmVOWqL3ADa1XHOT6+ayLJ3hDFD4RiS8XzQtjhTU6wykzEODLgahcqR PeEyh+gvZdPyvryuUPOKlN1gCkkjz7IqUUztzIIAjJwl63D/q2LJ3AywQzxGYhicQahm GA== Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3nwy9a1hk7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 23 Feb 2023 13:57:20 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA03.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 31NDvJN8006404 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 23 Feb 2023 13:57:19 GMT Received: from sbillaka-linux.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.41; Thu, 23 Feb 2023 05:57:13 -0800 From: Sankeerth Billakanti To: , , , Subject: [RFC PATCH 2/2] drm/msm/dp: enable pm_runtime support for dp driver Date: Thu, 23 Feb 2023 19:26:35 +0530 Message-ID: <20230223135635.30659-3-quic_sbillaka@quicinc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230223135635.30659-1-quic_sbillaka@quicinc.com> References: <20230223135635.30659-1-quic_sbillaka@quicinc.com> MIME-Version: 1.0 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-GUID: uYl-q6b2X_QfpoFRZts9uS-iQV8Aeoge X-Proofpoint-ORIG-GUID: uYl-q6b2X_QfpoFRZts9uS-iQV8Aeoge X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.170.22 definitions=2023-02-23_08,2023-02-23_01,2023-02-09_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 clxscore=1015 malwarescore=0 spamscore=0 priorityscore=1501 impostorscore=0 lowpriorityscore=0 adultscore=0 phishscore=0 mlxscore=0 mlxlogscore=999 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2302230114 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: quic_kalyant@quicinc.com, Sankeerth Billakanti , dianders@chromium.org, quic_bjorande@quicinc.com, quic_vproddut@quicinc.com, airlied@linux.ie, quic_abhinavk@quicinc.com, swboyd@chromium.org, seanpaul@chromium.org, dmitry.baryshkov@linaro.org, quic_khsieh@quicinc.com, sean@poorly.run Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The current DP driver directly enables or disables the necessary control resources based on code flow. This could disable a required resource that is needed in a different usecase. It can also lead to excessive voting of a resource and may increase power consumption. The pm_runtime framework can solve this problem in DP driver by monitoring the resource enable disable calls. This change will enable support for the pm_runtime resume and suspend operations for DP driver. Signed-off-by: Sankeerth Billakanti --- drivers/gpu/drm/msm/dp/dp_aux.c | 6 ++ drivers/gpu/drm/msm/dp/dp_display.c | 121 ++++++++++++++++------------ drivers/gpu/drm/msm/dp/dp_power.c | 7 -- 3 files changed, 76 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 5da95dfdeede..45026827bf7a 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -338,6 +338,7 @@ static ssize_t dp_aux_transfer_init(struct drm_dp_aux *dp_aux, return -EINVAL; } + pm_runtime_get_sync(dp_aux->dev); mutex_lock(&aux->mutex); if (!aux->initted) { ret = -EIO; @@ -418,6 +419,8 @@ static ssize_t dp_aux_transfer_init(struct drm_dp_aux *dp_aux, exit: mutex_unlock(&aux->mutex); + pm_runtime_mark_last_busy(dp_aux->dev); + pm_runtime_put_autosuspend(dp_aux->dev); return ret; } @@ -454,6 +457,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, return -EINVAL; } + pm_runtime_get_sync(dp_aux->dev); mutex_lock(&aux->mutex); if (!aux->initted) { ret = -EIO; @@ -527,6 +531,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, exit: mutex_unlock(&aux->mutex); + pm_runtime_mark_last_busy(dp_aux->dev); + pm_runtime_put_autosuspend(dp_aux->dev); return ret; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index a5dcef040b74..a23e79e43100 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -307,8 +307,10 @@ static void dp_display_unbind(struct device *dev, struct device *master, struct msm_drm_private *priv = dev_get_drvdata(master); /* disable all HPD interrupts */ - if (dp->core_initialized) + if (dp->core_initialized) { dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false); + pm_runtime_put_sync(dev); + } kthread_stop(dp->ev_tsk); @@ -1083,26 +1085,6 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) mutex_unlock(&dp_display->event_mutex); } -static void dp_display_config_hpd(struct dp_display_private *dp) -{ - - dp_display_host_init(dp); - dp_catalog_ctrl_hpd_config(dp->catalog); - - /* Enable plug and unplug interrupts only if requested */ - if (dp->dp_display.internal_hpd) - dp_catalog_hpd_config_intr(dp->catalog, - DP_DP_HPD_PLUG_INT_MASK | - DP_DP_HPD_UNPLUG_INT_MASK, - true); - - /* Enable interrupt first time - * we are leaving dp clocks on during disconnect - * and never disable interrupt - */ - enable_irq(dp->irq); -} - static int hpd_event_thread(void *data) { struct dp_display_private *dp_priv; @@ -1163,9 +1145,6 @@ static int hpd_event_thread(void *data) spin_unlock_irqrestore(&dp_priv->event_lock, flag); switch (todo->event_id) { - case EV_HPD_INIT_SETUP: - dp_display_config_hpd(dp_priv); - break; case EV_HPD_PLUG_INT: dp_hpd_plug_handle(dp_priv, todo->data); break; @@ -1337,16 +1316,12 @@ static int dp_display_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &dp->dp_display); - if (dp->dp_display.is_edp) { - dp_display_host_init(dp); - dp_display_host_phy_init(dp); - dp_catalog_ctrl_hpd_config(dp->catalog); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); + if (dp->dp_display.is_edp) { rc = devm_of_dp_aux_populate_bus(dp->aux, NULL); - - dp_display_host_phy_exit(dp); - dp_display_host_deinit(dp); - if (rc) { DRM_ERROR("failed to initialize panel, rc = %d\n", rc); goto error; @@ -1367,6 +1342,8 @@ static int dp_display_remove(struct platform_device *pdev) { struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); dp_display_deinit_sub_modules(dp); component_del(&pdev->dev, &dp_display_comp_ops); @@ -1375,6 +1352,42 @@ static int dp_display_remove(struct platform_device *pdev) return 0; } +static int dp_runtime_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); + dp_display_host_phy_exit(dp); + dp_display_host_deinit(dp); + + return 0; +} + +static int dp_runtime_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; + + dp = container_of(dp_display, struct dp_display_private, dp_display); + dp_display_host_init(dp); + + if (dp->dp_display.is_edp) { + dp_display_host_phy_init(dp); + } else { + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_HPD_PLUG_INT_MASK | + DP_DP_HPD_UNPLUG_INT_MASK, + true); + } + + dp_catalog_ctrl_hpd_config(dp->catalog); + + return 0; +} + static int dp_pm_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1384,6 +1397,9 @@ static int dp_pm_resume(struct device *dev) dp = container_of(dp_display, struct dp_display_private, dp_display); + if (pm_runtime_suspended(dev)) + return 0; + mutex_lock(&dp->event_mutex); drm_dbg_dp(dp->drm_dev, @@ -1394,16 +1410,7 @@ static int dp_pm_resume(struct device *dev) /* start from disconnected state */ dp->hpd_state = ST_DISCONNECTED; - /* turn on dp ctrl/phy */ - dp_display_host_init(dp); - - dp_catalog_ctrl_hpd_config(dp->catalog); - - if (dp->dp_display.internal_hpd) - dp_catalog_hpd_config_intr(dp->catalog, - DP_DP_HPD_PLUG_INT_MASK | - DP_DP_HPD_UNPLUG_INT_MASK, - true); + dp_runtime_resume(dev); if (dp_catalog_link_is_connected(dp->catalog)) { /* @@ -1452,27 +1459,29 @@ static int dp_pm_suspend(struct device *dev) dp = container_of(dp_display, struct dp_display_private, dp_display); + if (pm_runtime_suspended(dev)) + return 0; + 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, + "Before, type=%d sink=%d conn=%d core_inited=%d phy_inited=%d power_on=%d\n", + dp->dp_display.connector_type, dp->link->sink_count, + dp->dp_display.is_connected, 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_runtime_suspend(dev); 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, + "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.is_connected, dp->core_initialized, dp->phy_initialized, dp_display->power_on); mutex_unlock(&dp->event_mutex); @@ -1481,6 +1490,11 @@ static int dp_pm_suspend(struct device *dev) } static const struct dev_pm_ops dp_pm_ops = { + + SET_RUNTIME_PM_OPS(dp_runtime_suspend, dp_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + .suspend = dp_pm_suspend, .resume = dp_pm_resume, }; @@ -1521,8 +1535,11 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display) dp = container_of(dp_display, struct dp_display_private, dp_display); + /* enable host_init for HPD intr for DP */ if (!dp_display->is_edp) - dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0); + pm_runtime_get_sync(&dp->pdev->dev); + + enable_irq(dp->irq); } bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) @@ -1645,6 +1662,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge) return; } + pm_runtime_get_sync(&dp_display->pdev->dev); if (dp->is_edp) dp_hpd_plug_handle(dp_display, 0); @@ -1728,6 +1746,7 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge) drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); mutex_unlock(&dp_display->event_mutex); + pm_runtime_put_sync(&dp_display->pdev->dev); } void dp_bridge_mode_set(struct drm_bridge *drm_bridge, diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c index c0aaabb03389..a736d1b0f02f 100644 --- a/drivers/gpu/drm/msm/dp/dp_power.c +++ b/drivers/gpu/drm/msm/dp/dp_power.c @@ -172,8 +172,6 @@ int dp_power_client_init(struct dp_power *dp_power) power = container_of(dp_power, struct dp_power_private, dp_power); - pm_runtime_enable(&power->pdev->dev); - rc = dp_power_clk_init(power); if (rc) DRM_ERROR("failed to init clocks %d\n", rc); @@ -192,7 +190,6 @@ void dp_power_client_deinit(struct dp_power *dp_power) power = container_of(dp_power, struct dp_power_private, dp_power); - pm_runtime_disable(&power->pdev->dev); } int dp_power_init(struct dp_power *dp_power, bool flip) @@ -207,8 +204,6 @@ int dp_power_init(struct dp_power *dp_power, bool flip) power = container_of(dp_power, struct dp_power_private, dp_power); - pm_runtime_get_sync(&power->pdev->dev); - rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); if (rc) { DRM_ERROR("failed to enable DP core clocks, %d\n", rc); @@ -218,7 +213,6 @@ int dp_power_init(struct dp_power *dp_power, bool flip) return 0; exit: - pm_runtime_put_sync(&power->pdev->dev); return rc; } @@ -229,7 +223,6 @@ int dp_power_deinit(struct dp_power *dp_power) power = container_of(dp_power, struct dp_power_private, dp_power); dp_power_clk_enable(dp_power, DP_CORE_PM, false); - pm_runtime_put_sync(&power->pdev->dev); return 0; }