From patchwork Thu Nov 19 07:29:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Lee, Shawn C" X-Patchwork-Id: 11916637 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D65EC2D0E4 for ; Thu, 19 Nov 2020 07:25:00 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id CFC6121D7F for ; Thu, 19 Nov 2020 07:24:59 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CFC6121D7F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 37A0A89FFD; Thu, 19 Nov 2020 07:24:59 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7D32189FFD for ; Thu, 19 Nov 2020 07:24:57 +0000 (UTC) IronPort-SDR: +WtrzfJXIsTFput7r+RHasbgbXRQBKAJPAXK5Sc3hJWWgIz9qIV6CbWZNXU7Mfz9YmrP1JPlh7 P79xMqi/H1kw== X-IronPort-AV: E=McAfee;i="6000,8403,9809"; a="235391306" X-IronPort-AV: E=Sophos;i="5.77,489,1596524400"; d="scan'208";a="235391306" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Nov 2020 23:24:56 -0800 IronPort-SDR: qkPkNIdpBhsfvPF0GPurLx8QC1ehfzIK1Q3v4a0Zh4otG60/B2cFGVMUEMPtsYFlAuqPe5Vm6A cLRn1UXex/4Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,489,1596524400"; d="scan'208";a="368765389" Received: from shawnle1-build-machine.itwn.intel.com ([10.5.253.9]) by orsmga007.jf.intel.com with ESMTP; 18 Nov 2020 23:24:54 -0800 From: Lee Shawn C To: intel-gfx@lists.freedesktop.org Date: Thu, 19 Nov 2020 15:29:41 +0800 Message-Id: <20201119072941.32316-1-shawn.c.lee@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201116135913.20782-1-shawn.c.lee@intel.com> References: <20201116135913.20782-1-shawn.c.lee@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v4] drm/i915/lspcon: enter standby mode to enhance power saving X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Cooper Chiou Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" After system boot up, LSPCON will be configured as PCON mode. But it never go into power saving state. Source driver can do the following. Then LSPCON can enter standby mode automatically to save more power. 1. At PCON mode, source driver write 0x2 to DPCD 600h. 2. At LS mode, try to disable DP_DUAL_MODE_TMDS_OEN. v2: fix typo v3: Found particular monitor trigger HPD to LSPCON after main link stopped. If driver did not enable display output. Source should request LSPCON to enter standby mode again. v4: Before enter D3, make sure display output is not active. And source/sink are not doing link training. Cc: Ville Syrjälä Cc: Jani Nikula Cc: Uma Shankar Cc: Cooper Chiou Cc: Khaled Almahallawy Signed-off-by: Lee Shawn C --- drivers/gpu/drm/i915/display/intel_dp.c | 13 ++++++- drivers/gpu/drm/i915/display/intel_lspcon.c | 38 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_lspcon.h | 1 + 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ec8359f03aaf..d2567dc3bc5e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -6184,6 +6184,7 @@ static bool intel_dp_short_pulse(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp); u8 old_sink_count = intel_dp->sink_count; bool ret; @@ -6211,6 +6212,11 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) /* Handle CEC interrupts, if any */ drm_dp_cec_irq(&intel_dp->aux); + /* If LSPCON connected, try to set lspcon power state to D3 */ + if (lspcon && lspcon->active) + lspcon_standby(dp_to_dig_port(intel_dp), + intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base)); + /* defer to the hotplug work for link retraining if needed */ if (intel_dp_needs_link_retrain(intel_dp)) return false; @@ -6536,6 +6542,7 @@ intel_dp_detect(struct drm_connector *connector, struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum drm_connector_status status; @@ -6632,9 +6639,13 @@ intel_dp_detect(struct drm_connector *connector, intel_dp_check_service_irq(intel_dp); out: - if (status != connector_status_connected && !intel_dp->is_mst) + if (status != connector_status_connected && !intel_dp->is_mst) { intel_dp_unset_edid(intel_dp); + if (lspcon && lspcon->active) + lspcon_standby(dp_to_dig_port(intel_dp), false); + } + /* * Make sure the refs for power wells enabled during detect are * dropped to avoid a new detect cycle triggered by HPD polling. diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c index e37d45e531df..99eb67272552 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.c +++ b/drivers/gpu/drm/i915/display/intel_lspcon.c @@ -550,6 +550,44 @@ static bool lspcon_init(struct intel_digital_port *dig_port) return true; } +void lspcon_standby(struct intel_digital_port *dig_port, bool connected) +{ + struct intel_dp *dp = &dig_port->dp; + u8 align_status = 0, training_pattern = 0, i; + + if (connected) { + for (i = 0; i < 3; i++) { + usleep_range(10000, 11000); + + if (drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, + &align_status) <= 0) { + DRM_DEBUG_KMS("LSPCON failed to read align status\n"); + return; + } + + if (drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, + &training_pattern) <= 0) { + DRM_DEBUG_KMS("LSPCON failed to read training pattern set\n"); + return; + } + + /* + * If link trainig is ongoing. Or sink updated link align status. + * Source driver should not set lspcon power state to D3. + */ + if (align_status || training_pattern) { + DRM_DEBUG_KMS("LSPCON link training or display is working\n"); + DRM_DEBUG_KMS("LSPCON DPCD register 0102h = %x, 0204h = 0x%x\n", + training_pattern, align_status); + return; + } + } + } + + if (drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3) <= 0) + DRM_DEBUG_KMS("LSPCON failed to write power state to D3\n"); +} + void lspcon_resume(struct intel_digital_port *dig_port) { struct intel_lspcon *lspcon = &dig_port->lspcon; diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.h b/drivers/gpu/drm/i915/display/intel_lspcon.h index b03dcb7076d8..eef0e69bff32 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.h +++ b/drivers/gpu/drm/i915/display/intel_lspcon.h @@ -16,6 +16,7 @@ struct intel_encoder; struct intel_lspcon; void lspcon_resume(struct intel_digital_port *dig_port); +void lspcon_standby(struct intel_digital_port *dig_port, bool connected); void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon); void lspcon_write_infoframe(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state,