From patchwork Fri Feb 28 23:44:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rodrigo Vivi X-Patchwork-Id: 3745361 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A4D829F35F for ; Fri, 28 Feb 2014 23:45:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7538C2024D for ; Fri, 28 Feb 2014 23:45:54 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 482D2201BA for ; Fri, 28 Feb 2014 23:45:53 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4E0A0FBDED; Fri, 28 Feb 2014 15:45:51 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-yh0-f42.google.com (mail-yh0-f42.google.com [209.85.213.42]) by gabe.freedesktop.org (Postfix) with ESMTP id 4D183FBDD9 for ; Fri, 28 Feb 2014 15:45:14 -0800 (PST) Received: by mail-yh0-f42.google.com with SMTP id a41so1577851yho.1 for ; Fri, 28 Feb 2014 15:45:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=NwyabVbOH9YzV6cI4hVJcQFiy9dIc93X7oR+mMq6cuk=; b=ATxfkzGUl4WaEN/Bx58ND6sDDmp1KOaRti2rBYxnz6muYJamkuI895bMwJMhvIpawG p7Rzyqb9sBxLzYOW4I+xdR1T2Iqh/JMp284LtiN0nKfPwvGf9GGZd6MMlDCEN5muglvL DFPiCNJw16v47aIjcSWusbSOZ1OGFJ9x/RVtXhIMllZGY0UAbR1S9YIS5pdCjjAKyX8s MyyBjbTyksBaAksEMZc9jxp5wYQxv6xkxd5YlJP5yrt+a0bYMNnNoxp4VQRNCWJ9uwo1 eaHzB1ivWcqHHHgTBe4KEAx6SbPyVFlqK2mE1hGdE3Y7GP9uP6zRv6Vv3gZ1JKhehHzY fjQQ== X-Received: by 10.236.81.237 with SMTP id m73mr6481483yhe.29.1393631113845; Fri, 28 Feb 2014 15:45:13 -0800 (PST) Received: from localhost.localdomain ([189.67.129.152]) by mx.google.com with ESMTPSA id h23sm10769779yhc.0.2014.02.28.15.45.11 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Feb 2014 15:45:13 -0800 (PST) From: Rodrigo Vivi To: intel-gfx@lists.freedesktop.org Date: Fri, 28 Feb 2014 20:44:45 -0300 Message-Id: <1393631086-3880-11-git-send-email-rodrigo.vivi@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1393631086-3880-1-git-send-email-rodrigo.vivi@gmail.com> References: <1393631086-3880-1-git-send-email-rodrigo.vivi@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 10/11] drm/i915: PSR Baytrail: Force exit by inactivating it. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Baytrail cannot easily detect screen updates and force PSR exit. So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy} and update to enable it back it later with a delayed workqueue. Cc: Chris Wilson Cc: Ville Syrjälä Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem.c | 12 +++++ drivers/gpu/drm/i915/intel_display.c | 24 ++++++++- drivers/gpu/drm/i915/intel_dp.c | 99 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 1 + 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 18f457e..a4e666c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -785,6 +785,8 @@ struct i915_psr { bool sink_support; bool source_ok; bool setup_done; + bool active; + struct delayed_work work; void (*setup)(struct intel_dp *intel_dp); void (*enable_sink)(struct intel_dp *intel_dp); void (*enable_source)(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3618bb0..c6bfc81 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1251,6 +1251,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, goto unlock; } + /* Here we don't reschedule work to get PSR back because userspace + * can set domain and take as much as time it wants to write it. + * We only reschedule it back on next finish_page_flip. There is the + * risk of PSR be inactive forever depending on how compositor works, + * but this is the safest way to avoid loosing screen updates. + */ + intel_edp_psr_exit(dev, false); + /* Try to flush the object off the GPU without holding the lock. * We will repeat the flush holding the lock in the normal manner * to catch cases where we are gazumped. @@ -1296,6 +1304,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, if (ret) return ret; + intel_edp_psr_exit(dev, true); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; @@ -3982,6 +3992,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, if (ret) return ret; + intel_edp_psr_exit(dev, true); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 26196b8..5e4c768 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4433,6 +4433,8 @@ static void intel_connector_check_state(struct intel_connector *connector) * consider. */ void intel_connector_dpms(struct drm_connector *connector, int mode) { + struct drm_device *dev = connector->dev; + struct intel_encoder *intel_encoder; /* All the simple cases only support two dpms states. */ if (mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; @@ -4443,9 +4445,15 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) connector->dpms = mode; /* Only need to change hw state when actually enabled */ - if (connector->encoder) - intel_encoder_dpms(to_intel_encoder(connector->encoder), mode); + if (connector->encoder) { + + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder_dpms(intel_encoder, mode); + if (intel_encoder->type == INTEL_OUTPUT_EDP && + mode == DRM_MODE_DPMS_OFF) + intel_edp_psr_exit(dev, false); + } intel_modeset_check_state(connector->dev); } @@ -7512,6 +7520,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, if (!visible && !intel_crtc->cursor_visible) return; + intel_edp_psr_exit(dev, true); + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) { I915_WRITE(CURPOS_IVB(pipe), pos); ivb_update_cursor(crtc, base); @@ -8224,12 +8234,15 @@ void intel_mark_idle(struct drm_device *dev) gen6_rps_idle(dev->dev_private); } + void intel_mark_fb_busy(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring) { struct drm_device *dev = obj->base.dev; struct drm_crtc *crtc; + intel_edp_psr_exit(dev, true); + if (!i915.powersave) return; @@ -8330,6 +8343,10 @@ static void do_intel_finish_page_flip(struct drm_device *dev, queue_work(dev_priv->wq, &work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); + + /* Get PSR back after set_domain inactivated it + * without rescheduling it back. */ + intel_edp_psr_update(dev); } void intel_finish_page_flip(struct drm_device *dev, int pipe) @@ -8696,6 +8713,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (work == NULL) return -ENOMEM; + /* Exit PSR early in page flip */ + intel_edp_psr_exit(dev, true); + work->event = event; work->crtc = crtc; work->old_fb_obj = to_intel_framebuffer(old_fb)->obj; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3adc127..f386860 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1883,6 +1883,8 @@ static void intel_edp_psr_do_enable(struct intel_dp *intel_dp) /* Enable PSR on the host */ dev_priv->psr.enable_source(intel_dp); + + dev_priv->psr.active = true; } void intel_edp_psr_enable(struct intel_dp *intel_dp) @@ -1919,6 +1921,8 @@ void vlv_edp_psr_disable(struct intel_dp *intel_dp) if (!dev_priv->psr.setup_done) return; + intel_edp_psr_exit(dev, false); + if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) & VLV_EDP_PSR_IN_TRANS) == 0, 250)) WARN(1, "PSR transition took longer than expected\n"); @@ -1947,18 +1951,11 @@ void intel_edp_psr_disable(struct intel_dp *intel_dp) DRM_ERROR("Timed out waiting for PSR Idle State\n"); } -void intel_edp_psr_update(struct drm_device *dev) +void intel_edp_psr_do_update(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; struct intel_dp *intel_dp = NULL; - if (!HAS_PSR(dev)) - return; - - if (!dev_priv->psr.setup_done) - return; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) if (encoder->type == INTEL_OUTPUT_EDP) { intel_dp = enc_to_intel_dp(&encoder->base); @@ -1973,6 +1970,90 @@ void intel_edp_psr_update(struct drm_device *dev) } } +void intel_edp_psr_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!HAS_PSR(dev)) + return; + + if (!dev_priv->psr.setup_done) + return; + + if (IS_VALLEYVIEW(dev)) + intel_edp_psr_exit(dev, true); + else + intel_edp_psr_do_update(dev); +} + +void intel_edp_psr_work(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), psr.work.work); + struct drm_device *dev = dev_priv->dev; + + intel_edp_psr_do_update(dev); +} + +void intel_edp_psr_inactivate(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *connector; + struct intel_encoder *encoder; + struct intel_crtc *intel_crtc; + struct intel_dp *intel_dp = NULL; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + + if (connector->base.dpms != DRM_MODE_DPMS_ON) + continue; + + encoder = to_intel_encoder(connector->base.encoder); + if (encoder->type == INTEL_OUTPUT_EDP) { + + intel_dp = enc_to_intel_dp(&encoder->base); + intel_crtc = to_intel_crtc(encoder->base.crtc); + + if (!vlv_edp_is_psr_enabled_on_pipe(dev, + intel_crtc->pipe)) + continue; + + dev_priv->psr.active = false; + + I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), + VLV_EDP_PSR_RESET); + /* WaClearPSRReset:vlv */ + I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), 0); + + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + } + } +} + +void intel_edp_psr_exit(struct drm_device *dev, bool schedule_back) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!HAS_PSR(dev)) + return; + + if (!IS_VALLEYVIEW(dev)) + return; + + if (!dev_priv->psr.setup_done) + return; + + cancel_delayed_work_sync(&dev_priv->psr.work); + + if (dev_priv->psr.active) + intel_edp_psr_inactivate(dev); + + if (schedule_back) + schedule_delayed_work(&dev_priv->psr.work, + msecs_to_jiffies(5000)); +} + void intel_edp_psr_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1980,6 +2061,8 @@ void intel_edp_psr_init(struct drm_device *dev) if (!HAS_PSR(dev)) return; + INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work); + if (IS_VALLEYVIEW(dev)) { dev_priv->psr.setup = vlv_edp_psr_setup; dev_priv->psr.enable_sink = vlv_edp_psr_enable_sink; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2e4516d..47b8c9f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -757,6 +757,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); void intel_edp_psr_disable(struct intel_dp *intel_dp); void intel_edp_psr_update(struct drm_device *dev); +void intel_edp_psr_exit(struct drm_device *dev, bool schedule_back); void intel_edp_psr_init(struct drm_device *dev);