From patchwork Mon Feb 25 22:55:20 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rodrigo Vivi X-Patchwork-Id: 2183061 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id D0022DF230 for ; Mon, 25 Feb 2013 23:03:55 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D04C1E632C for ; Mon, 25 Feb 2013 15:03:55 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-gg0-f169.google.com (mail-gg0-f169.google.com [209.85.161.169]) by gabe.freedesktop.org (Postfix) with ESMTP id 0CC7CE5CD2; Mon, 25 Feb 2013 14:55:50 -0800 (PST) Received: by mail-gg0-f169.google.com with SMTP id j5so593356ggn.28 for ; Mon, 25 Feb 2013 14:55:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=xVYIYNPMmXaCnLJFxIreSgLafC4lOoUXIC4G2DHogV4=; b=kYN9NCStiUcoU1JGNBGh7ciDjz6NjfEy++e/PHrNimILnVrFag5cvYkQ+aSLEQRImi d67C5rKuRMczcQeaemqiPhWbHwn2ZTyeR//sibWHEjIeVKAg0ysz6R3DAgOHV//BU7ZZ wa8AiKMH7QNC2C0WMYS3Ig+wD0cH/N4tWtg3cyqsRtodfGG03Vhs8rgf4QW03PvI1chZ M4kiDBeCVD8Ja7xxLcuEdVwVB18oVCyJX3ru5zWUVG6AlhWYa2Rj1nKdqedFOZqFyCY7 eSVUQqqMq3Up2lybOv/SUVAp3BjThyhJVPdr8alLXjhIehtJYumxOHdFmytJZ3y5o1gN vGGA== X-Received: by 10.236.132.169 with SMTP id o29mr21152230yhi.88.1361832950225; Mon, 25 Feb 2013 14:55:50 -0800 (PST) Received: from localhost.localdomain ([186.204.164.107]) by mx.google.com with ESMTPS id w7sm28350950yhj.0.2013.02.25.14.55.48 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 25 Feb 2013 14:55:49 -0800 (PST) From: Rodrigo Vivi To: intel-gfx@lists.freedesktop.org Subject: [PATCH 6/8] drm/i915: Enable/Disable PSR Date: Mon, 25 Feb 2013 19:55:20 -0300 Message-Id: <1361832922-19801-7-git-send-email-rodrigo.vivi@gmail.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1361832922-19801-1-git-send-email-rodrigo.vivi@gmail.com> References: <1361832922-19801-1-git-send-email-rodrigo.vivi@gmail.com> Cc: dri-devel@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Adding Enable and Disable PSR functionalities. This includes setting the PSR configuration over AUX, sending SDP VSC DIP over the eDP PIPE config, enabling PSR in the sink via DPCD register and finally enabling PSR on the host. This patch is heavily based on initial PSR code by Sateesh Kavuri and Kumar Shobhit but in a different implementation. Credits-by: Sateesh Kavuri Credits-by: Shobhit Kumar Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_reg.h | 40 +++++++++ drivers/gpu/drm/i915/intel_dp.c | 183 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 3 + 3 files changed, 226 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b715ecd..1e31f23 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -844,6 +844,8 @@ #define SNB_CPU_FENCE_ENABLE (1<<29) #define DPFC_CPU_FENCE_OFFSET 0x100104 +/* Framebuffer compression for Haswell */ +#define HSW_FBC_CONTROL 0x43208 /* * GPIO regs @@ -1580,6 +1582,44 @@ #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B) #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B) +/* HSW eDP PSR registers */ +#define EDP_PSR_CTL 0x64800 +#define EDP_PSR_ENABLE (1<<31) +#define EDP_PSR_LINK_DISABLE (0<<27) +#define EDP_PSR_LINK_STANDBY (1<<27) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_MASK (3<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES (0<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES (1<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES (2<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES (3<<25) +#define EDP_PSR_MAX_SLEEP_TIME_SHIFT 20 +#define EDP_PSR_SKIP_AUX_EXIT (1<<12) +#define EDP_PSR_TP1_TP2_SEL (0<<11) +#define EDP_PSR_TP1_TP3_SEL (1<<11) +#define EDP_PSR_TP2_TP3_TIME_500us (0<<8) +#define EDP_PSR_TP2_TP3_TIME_100us (1<<8) +#define EDP_PSR_TP2_TP3_TIME_2500us (2<<8) +#define EDP_PSR_TP2_TP3_TIME_0us (3<<8) +#define EDP_PSR_TP1_TIME_500us (0<<4) +#define EDP_PSR_TP1_TIME_100us (1<<4) +#define EDP_PSR_TP1_TIME_2500us (2<<4) +#define EDP_PSR_TP1_TIME_0us (3<<4) +#define EDP_PSR_IDLE_FRAME_SHIFT 0 + +#define EDP_PSR_AUX_CTL 0x64810 +#define EDP_PSR_AUX_DATA1 0x64814 +#define EDP_PSR_AUX_DATA2 0x64818 +#define EDP_PSR_AUX_DATA3 0x6481c +#define EDP_PSR_AUX_DATA4 0x64820 +#define EDP_PSR_AUX_DATA5 0x64824 + +#define EDP_PSR_STATUS_CTL 0x64840 +#define EDP_PSR_STATUS_STATE_MASK (7<<29) + +#define EDP_PSR_DEBUG_CTL 0x64860 +#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26) +#define EDP_PSR_DEBUG_MASK_HPD (1<<25) + /* VGA port control */ #define ADPA 0x61100 #define PCH_ADPA 0xe1100 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5cfa9f4..a420f0d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -83,6 +83,13 @@ static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) return intel_dig_port->base.base.dev; } +static struct drm_crtc *intel_dp_to_crtc(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + + return intel_dig_port->base.base.crtc; +} + static struct intel_dp *intel_attached_dp(struct drm_connector *connector) { return enc_to_intel_dp(&intel_attached_encoder(connector)->base); @@ -1443,6 +1450,182 @@ static bool is_edp_psr(struct intel_dp *intel_dp) (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED)); } +static bool +intel_edp_is_psr_enabled(struct intel_dp* intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; +} + +static void +intel_edp_psr_enable_src(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t max_sleep_time = 0x1f; + uint32_t val = 0x0; + + if (dev_priv->vbt.psr_idle_frames) + val |= dev_priv->vbt.psr_idle_frames << EDP_PSR_IDLE_FRAME_SHIFT; + else + val |= 1 << EDP_PSR_IDLE_FRAME_SHIFT; + + if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) { + val |= EDP_PSR_LINK_STANDBY; + val |= EDP_PSR_TP2_TP3_TIME_0us; + val |= EDP_PSR_TP1_TIME_0us; + val |= EDP_PSR_SKIP_AUX_EXIT; + } else { + val |= EDP_PSR_LINK_DISABLE; + /* Use these Values from VBT + * Case values are timings for HSW as of now + * in multiple of 100us + */ + switch(dev_priv->vbt.psr_wakeup_tp1) { + case 1: + val |= EDP_PSR_TP1_TIME_100us; + break; + case 5: + val |= EDP_PSR_TP1_TIME_500us; + break; + case 25: + val |= EDP_PSR_TP1_TIME_2500us; + break; + default: + val |= EDP_PSR_TP1_TIME_500us; + break; + }; + switch(dev_priv->vbt.psr_wakeup_tp2_tp3) { + case 1: + val |= EDP_PSR_TP2_TP3_TIME_100us; + break; + case 5: + val |= EDP_PSR_TP2_TP3_TIME_500us; + break; + case 25: + val |= EDP_PSR_TP2_TP3_TIME_2500us; + break; + default: + val |= EDP_PSR_TP2_TP3_TIME_500us; + break; + }; + } + + I915_WRITE(EDP_PSR_CTL, val | + EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES | + max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT | + EDP_PSR_ENABLE); +} + +void intel_edp_write_vsc_psr(struct intel_dp* intel_dp, + struct edp_vsc_psr *vsc_psr) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp_to_crtc(intel_dp)); + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->cpu_transcoder); + u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(intel_crtc->cpu_transcoder); + uint32_t *data = (uint32_t *)vsc_psr; + unsigned int i; + u32 val = I915_READ(ctl_reg); + + if (data_reg == 0) + return; + + /* As per eDP spec, wait for vblank to send SDP VSC packet */ + intel_wait_for_vblank(dev, intel_crtc->pipe); + + mmiowb(); + for (i = 0; i < sizeof(struct edp_vsc_psr); i += 4) { + I915_WRITE(data_reg + i, *data); + data++; + } + /* Write every possible data byte to force correct ECC calculation. */ + for (; i < VIDEO_DIP_DATA_SIZE; i += 4) + I915_WRITE(data_reg + i, 0); + mmiowb(); + + val |= VIDEO_DIP_ENABLE_VSC_HSW; + I915_WRITE(ctl_reg, val); + POSTING_READ(ctl_reg); +} + +void intel_edp_enable_psr(struct intel_dp* intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct edp_vsc_psr psr_vsc; + int msg_size = 5; /* Header(4) + Message(1) */ + + if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(intel_dp)) + return; + + /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */ + memset(&psr_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.id = 0; + psr_vsc.sdp_header.type = 0x7; + psr_vsc.sdp_header.revision = 0x2; + psr_vsc.sdp_header.valid_payload_bytes = 0x8; + + intel_edp_write_vsc_psr(intel_dp, &psr_vsc); + + /* Enable PSR in sink by setting bit 0 in DPCD config reg + * along with the transmitter state during PSR active + * Transmitter state later can be ready from VBT. As of now + * program the full link down + * + */ + intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, + DP_PSR_ENABLE); + + /* Setup AUX registers */ + /* Write command on DPCD 0x0600 */ + I915_WRITE(EDP_PSR_AUX_DATA1, 0x80060000); + + /* Set the state to normal operation D0 in DPCD 0x0600 */ + I915_WRITE(EDP_PSR_AUX_DATA2, 0x01000000); + + I915_WRITE(EDP_PSR_AUX_CTL, + msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT | + I915_READ(DPA_AUX_CH_CTL)); + + /* Enable PSR on the host */ + intel_edp_psr_enable_src(intel_dp); + + /* WA: FBC/PSR Underrun/Corruption Workaround */ + I915_WRITE(HSW_FBC_CONTROL, ~FBC_CTL_EN); + + /* WA: Continuous PSR exit Workaround */ + I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP); + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); +} + +void intel_edp_disable_psr(struct intel_dp* intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp_to_crtc(intel_dp)); + uint32_t reg = HSW_TVIDEO_DIP_CTL(intel_crtc->cpu_transcoder); + uint32_t val; + + if (!intel_edp_is_psr_enabled(intel_dp)) + return; + + val = I915_READ(EDP_PSR_CTL); + I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE); + + /* Wait till PSR is idle */ + if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) & + EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10)) + DRM_ERROR("Timed out waiting for PSR Idle State\n"); + + intel_wait_for_vblank(dev, intel_crtc->pipe); + + val = I915_READ(reg); + I915_WRITE(reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW); +} + static void intel_enable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 865ede6..cfda739 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -696,4 +696,7 @@ extern bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); +extern void intel_edp_enable_psr(struct intel_dp* intel_dp); +extern void intel_edp_disable_psr(struct intel_dp* intel_dp); + #endif /* __INTEL_DRV_H__ */