From patchwork Tue Oct 7 15:09:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: vandana.kannan@intel.com X-Patchwork-Id: 5046561 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 ACC0F9F349 for ; Tue, 7 Oct 2014 14:55:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7D34120220 for ; Tue, 7 Oct 2014 14:55:22 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 3CC6820221 for ; Tue, 7 Oct 2014 14:55:21 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7C4428918E; Tue, 7 Oct 2014 07:55:20 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id 3C02D8918E for ; Tue, 7 Oct 2014 07:55:19 -0700 (PDT) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 07 Oct 2014 07:55:18 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.04,670,1406617200"; d="scan'208";a="610839845" Received: from vkannan-desktop.iind.intel.com ([10.223.25.137]) by fmsmga002.fm.intel.com with ESMTP; 07 Oct 2014 07:54:49 -0700 From: Vandana Kannan To: intel-gfx@lists.freedesktop.org Date: Tue, 7 Oct 2014 20:39:40 +0530 Message-Id: <1412694584-743-3-git-send-email-vandana.kannan@intel.com> X-Mailer: git-send-email 2.0.1 In-Reply-To: <1412694584-743-1-git-send-email-vandana.kannan@intel.com> References: <1412694584-743-1-git-send-email-vandana.kannan@intel.com> Subject: [Intel-gfx] [RFC 2/6] drm/i915: Define PPS setup functions X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, 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 Defining functions equivalent to intel_dp_panel_power_sequencer. In the setup part, the differnce between vlv and other platforms is only w.r.t registers. Other parts like reading VBT are common. Signed-off-by: Vandana Kannan --- drivers/gpu/drm/i915/intel_display.c | 1 + drivers/gpu/drm/i915/intel_dp.c | 31 ++----- drivers/gpu/drm/i915/intel_drv.h | 8 ++ drivers/gpu/drm/i915/intel_panel.c | 153 +++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b8488a8..22529b9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12632,6 +12632,7 @@ static void intel_init_display(struct drm_device *dev) } intel_panel_init_backlight_funcs(dev); + intel_panel_init_pps_funcs(dev); mutex_init(&dev_priv->pps_mutex); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9113497..861b634 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -322,7 +322,7 @@ static void pps_unlock(struct intel_dp *intel_dp) intel_display_power_put(dev_priv, power_domain); } -static enum pipe +enum pipe vlv_power_sequencer_pipe(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -419,13 +419,12 @@ vlv_initial_pps_pipe(struct drm_i915_private *dev_priv, return INVALID_PIPE; } -static void -vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp) +void +vlv_initial_power_sequencer_setup(struct intel_digital_port *intel_dig_port) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct edp_power_seq power_seq; enum port port = intel_dig_port->port; lockdep_assert_held(&dev_priv->pps_mutex); @@ -452,10 +451,6 @@ vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp) DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n", port_name(port), pipe_name(intel_dp->pps_pipe)); - - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); } void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv) @@ -1366,7 +1361,7 @@ static void edp_wait_backlight_off(struct intel_dp *intel_dp) * is locked */ -static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) +u32 ironlake_get_pp_control(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -5034,9 +5029,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, return false; } - /* We now know it's not a ghost, init power sequence regs. */ pps_lock(intel_dp); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq); + intel_dp_init_panel_power_timestamps(intel_dp); + intel_panel_setup_panel_power_sequencer(intel_connector); pps_unlock(intel_dp); mutex_lock(&dev->mode_config.mutex); @@ -5176,18 +5171,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } - if (is_edp(intel_dp)) { - pps_lock(intel_dp); - if (IS_VALLEYVIEW(dev)) { - vlv_initial_power_sequencer_setup(intel_dp); - } else { - intel_dp_init_panel_power_timestamps(intel_dp); - intel_dp_init_panel_power_sequencer(dev, intel_dp, - &power_seq); - } - pps_unlock(intel_dp); - } - intel_dp_aux_init(intel_dp, intel_connector); /* init MST on ports that can support it */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ddf839d..8f4332e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -989,7 +989,12 @@ void intel_dp_mst_suspend(struct drm_device *dev); void intel_dp_mst_resume(struct drm_device *dev); int intel_dp_max_link_bw(struct intel_dp *intel_dp); void intel_dp_hot_plug(struct intel_encoder *intel_encoder); +enum pipe vlv_power_sequencer_pipe(struct intel_dp *intel_dp); +void vlv_initial_power_sequencer_setup( + struct intel_digital_port *intel_dig_port); void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv); +u32 ironlake_get_pp_control(struct intel_dp *intel_dp); + /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port); @@ -1089,6 +1094,9 @@ extern struct drm_display_mode *intel_find_panel_downclock( struct drm_device *dev, struct drm_display_mode *fixed_mode, struct drm_connector *connector); +void intel_panel_setup_panel_power_sequencer( + struct intel_connector *connector); +void intel_panel_init_pps_funcs(struct drm_device *dev); /* intel_pm.c */ void intel_init_clock_gating(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 543e0f1..cfb6e9d 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1344,6 +1344,159 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) } } + +static struct edp_power_seq pch_get_pps_registers( + struct intel_connector *connector, + u32 pp_ctrl_reg, u32 pp_on_reg, + u32 pp_off_reg, u32 pp_div_reg) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder = connector->base.encoder; + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct edp_power_seq cur; + u32 pp_on, pp_off, pp_div, pp; + + pp_on = I915_READ(pp_on_reg); + pp_off = I915_READ(pp_off_reg); + pp_div = I915_READ(pp_div_reg); + + /* Workaround: Need to write PP_CONTROL with the unlock key as + * the very first thing. */ + pp = ironlake_get_pp_control(&intel_dig_port->dp); + I915_WRITE(pp_ctrl_reg, pp); + + /* Pull timing values out of registers */ + cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> + PANEL_POWER_UP_DELAY_SHIFT; + + cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >> + PANEL_LIGHT_ON_DELAY_SHIFT; + + cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >> + PANEL_LIGHT_OFF_DELAY_SHIFT; + + cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> + PANEL_POWER_DOWN_DELAY_SHIFT; + + cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> + PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000; + + DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", + cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); + + return cur; +} + +static struct edp_power_seq pch_setup_pps(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg; + + lockdep_assert_held(&dev_priv->pps_mutex); + + pp_ctrl_reg = PCH_PP_CONTROL; + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_div_reg = PCH_PP_DIVISOR; + + return pch_get_pps_registers(connector, pp_ctrl_reg, pp_on_reg, + pp_off_reg, pp_div_reg); +} + +static struct edp_power_seq vlv_setup_pps(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder = connector->base.encoder; + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + enum pipe pipe = vlv_power_sequencer_pipe(&intel_dig_port->dp); + int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg; + + vlv_initial_power_sequencer_setup(intel_dig_port); + + lockdep_assert_held(&dev_priv->pps_mutex); + + pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe); + pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe); + pp_off_reg = VLV_PIPE_PP_OFF_DELAYS(pipe); + pp_div_reg = VLV_PIPE_PP_DIVISOR(pipe); + + return pch_get_pps_registers(connector, pp_ctrl_reg, pp_on_reg, + pp_off_reg, pp_div_reg); +} + +void intel_panel_setup_panel_power_sequencer(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + struct edp_power_seq cur, spec, vbt, final; + + /* Get chip specific register values */ + cur = dev_priv->display.setup_panel_power_seq(connector); + + vbt = dev_priv->vbt.edp_pps; + + /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of + * our hw here, which are all in 100usec. */ + spec.t1_t3 = 210 * 10; + spec.t8 = 50 * 10; /* no limit for t8, use t7 instead */ + spec.t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */ + spec.t10 = 500 * 10; + /* This one is special and actually in units of 100ms, but zero + * based in the hw (so we need to add 100 ms). But the sw vbt + * table multiplies it with 1000 to make it in units of 100usec, + * too. */ + spec.t11_t12 = (510 + 100) * 10; + + DRM_DEBUG_KMS("vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", + vbt.t1_t3, vbt.t8, vbt.t9, vbt.t10, vbt.t11_t12); + + /* Use the max of the register settings and vbt. If both are + * unset, fall back to the spec limits. */ +#define assign_final(field) final.field = (max(cur.field, vbt.field) == 0 ? \ + spec.field : \ + max(cur.field, vbt.field)) + assign_final(t1_t3); + assign_final(t8); + assign_final(t9); + assign_final(t10); + assign_final(t11_t12); +#undef assign_final + +#define get_delay(field) (DIV_ROUND_UP(final.field, 10)) + panel->pps.panel_power_up_delay = get_delay(t1_t3); + panel->pps.backlight_on_delay = get_delay(t8); + panel->pps.backlight_off_delay = get_delay(t9); + panel->pps.panel_power_down_delay = get_delay(t10); + panel->pps.panel_power_cycle_delay = get_delay(t11_t12); +#undef get_delay + + DRM_DEBUG_KMS("panel power up delay %d, power down delay %d," + "power cycle delay %d\n", + panel->pps.panel_power_up_delay, + panel->pps.panel_power_down_delay, + panel->pps.panel_power_cycle_delay); + + DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", + panel->pps.backlight_on_delay, + panel->pps.backlight_off_delay); + +} + +/* Setup chip specific PPS functions */ +void intel_panel_init_pps_funcs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_VALLEYVIEW(dev)) + dev_priv->display.setup_panel_power_seq = vlv_setup_pps; + else + dev_priv->display.setup_panel_power_seq = pch_setup_pps; +} + int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, struct drm_display_mode *downclock_mode)