[RFC 3/6] drm/i915: Program PPS registers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Actually set values into PPS related registers. This implementation is
equivalent to intel_dp_panel_power_sequencer_registers where the values
saved intially are written into registers.

Signed-off-by: Vandana Kannan <vandana.kannan@xxxxxxxxx>
---
 drivers/gpu/drm/i915/intel_dp.c    |   4 +-
 drivers/gpu/drm/i915/intel_drv.h   |   3 ++
 drivers/gpu/drm/i915/intel_panel.c | 102 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 861b634..a40d494 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -248,7 +248,7 @@ unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
 }
 
 /* hrawclock is 1/4 the FSB frequency */
-static int
+int
 intel_hrawclk(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5005,6 +5005,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 	bool has_dpcd;
 	struct drm_display_mode *scan;
 	struct edid *edid;
+	enum port port = intel_dig_port->port;
 
 	intel_dp->drrs_state.type = DRRS_NOT_SUPPORTED;
 
@@ -5032,6 +5033,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 	pps_lock(intel_dp);
 	intel_dp_init_panel_power_timestamps(intel_dp);
 	intel_panel_setup_panel_power_sequencer(intel_connector);
+	intel_panel_set_pps_registers(intel_connector, port);
 	pps_unlock(intel_dp);
 
 	mutex_lock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8f4332e..687d581 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -994,6 +994,7 @@ 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);
+int intel_hrawclk(struct drm_device *dev);
 
 /* intel_dp_mst.c */
 int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
@@ -1096,6 +1097,8 @@ extern struct drm_display_mode *intel_find_panel_downclock(
 				struct drm_connector *connector);
 void intel_panel_setup_panel_power_sequencer(
 				struct intel_connector *connector);
+void intel_panel_set_pps_registers(struct intel_connector *connector,
+				enum port port);
 void intel_panel_init_pps_funcs(struct drm_device *dev);
 
 /* intel_pm.c */
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index cfb6e9d..9f7cb7a 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -1486,15 +1486,113 @@ void intel_panel_setup_panel_power_sequencer(struct intel_connector *connector)
 
 }
 
+static void vlv_set_pps_registers(struct intel_connector *connector,
+		enum port port, int *pp_ctrl_reg,
+		int *pp_on_reg, int *pp_off_reg,
+		int *pp_div_reg, int *port_sel, int *div)
+{
+	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 = PIPE_A;
+
+	pipe = vlv_power_sequencer_pipe(&intel_dig_port->dp);
+
+	lockdep_assert_held(&dev_priv->pps_mutex);
+
+	*pp_ctrl_reg = 0;
+	*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);
+
+	*port_sel = PANEL_PORT_SELECT_VLV(port);
+	*div = intel_hrawclk(dev);
+}
+
+static void pch_set_pps_registers(struct intel_connector *connector,
+		enum port port, int *pp_ctrl_reg,
+		int *pp_on_reg, int *pp_off_reg,
+		int *pp_div_reg, int *port_sel, int *div)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	lockdep_assert_held(&dev_priv->pps_mutex);
+
+	*pp_ctrl_reg = 0;
+	*pp_on_reg = PCH_PP_ON_DELAYS;
+	*pp_off_reg = PCH_PP_OFF_DELAYS;
+	*pp_div_reg = PCH_PP_DIVISOR;
+
+	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
+		if (port == PORT_A)
+			*port_sel = PANEL_PORT_SELECT_DPA;
+		else
+			*port_sel = PANEL_PORT_SELECT_DPD;
+	}
+	*div = intel_pch_rawclk(dev);
+}
+
+void intel_panel_set_pps_registers(struct intel_connector *connector,
+				enum port port)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_panel *panel = &connector->panel;
+	int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg;
+	u32 pp_on, pp_off, pp_div;
+	u32 port_sel = 0, div;
+
+	dev_priv->display.set_pps_registers(connector, port, &pp_ctrl_reg,
+				&pp_on_reg, &pp_off_reg, &pp_div_reg,
+				&port_sel, &div);
+
+	/*
+	 * And finally store the new values in the power sequencer. The
+	 * backlight delays are set to 1 because we do manual waits on them. For
+	 * T8, even BSpec recommends doing it. For T9, if we don't do this,
+	 * we'll end up waiting for the backlight off delay twice: once when we
+	 * do the manual sleep, and once when we disable the panel and wait for
+	 * the PP_STATUS bit to become zero.
+	 */
+	pp_on = (panel->pps.panel_power_up_delay <<
+			PANEL_POWER_UP_DELAY_SHIFT) |
+		(1 << PANEL_LIGHT_ON_DELAY_SHIFT);
+	pp_off = (1 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
+		(panel->pps.panel_power_down_delay <<
+		 PANEL_POWER_DOWN_DELAY_SHIFT);
+	/* Compute the divisor for the pp clock, simply match the Bspec
+	 * formula. */
+	pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT;
+	pp_div |= (DIV_ROUND_UP(panel->pps.panel_power_cycle_delay, 1000)
+			<< PANEL_POWER_CYCLE_DELAY_SHIFT);
+
+	pp_on |= port_sel;
+
+	I915_WRITE(pp_on_reg, pp_on);
+	I915_WRITE(pp_off_reg, pp_off);
+	I915_WRITE(pp_div_reg, pp_div);
+
+	DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
+			I915_READ(pp_on_reg),
+			I915_READ(pp_off_reg),
+			I915_READ(pp_div_reg));
+
+}
+
 /* 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))
+	if (IS_VALLEYVIEW(dev)) {
 		dev_priv->display.setup_panel_power_seq = vlv_setup_pps;
-	else
+		dev_priv->display.set_pps_registers = vlv_set_pps_registers;
+	} else {
 		dev_priv->display.setup_panel_power_seq = pch_setup_pps;
+		dev_priv->display.set_pps_registers = pch_set_pps_registers;
+	}
 }
 
 int intel_panel_init(struct intel_panel *panel,
-- 
2.0.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux