|
@@ -4751,6 +4751,18 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
|
|
|
I915_READ(pp_div_reg));
|
|
I915_READ(pp_div_reg));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * intel_dp_set_drrs_state - program registers for RR switch to take effect
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ * @refresh_rate: RR to be programmed
|
|
|
|
|
+ *
|
|
|
|
|
+ * This function gets called when refresh rate (RR) has to be changed from
|
|
|
|
|
+ * one frequency to another. Switches can be between high and low RR
|
|
|
|
|
+ * supported by the panel or to any other RR based on media playback (in
|
|
|
|
|
+ * this case, RR value needs to be passed from user space).
|
|
|
|
|
+ *
|
|
|
|
|
+ * The caller of this function needs to take a lock on dev_priv->drrs.
|
|
|
|
|
+ */
|
|
|
static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
|
static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
|
|
{
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
@@ -4843,6 +4855,12 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
|
|
DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
|
|
DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * intel_edp_drrs_enable - init drrs struct if supported
|
|
|
|
|
+ * @intel_dp: DP struct
|
|
|
|
|
+ *
|
|
|
|
|
+ * Initializes frontbuffer_bits and drrs.dp
|
|
|
|
|
+ */
|
|
|
void intel_edp_drrs_enable(struct intel_dp *intel_dp)
|
|
void intel_edp_drrs_enable(struct intel_dp *intel_dp)
|
|
|
{
|
|
{
|
|
|
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
|
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
|
@@ -4870,6 +4888,11 @@ unlock:
|
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * intel_edp_drrs_disable - Disable DRRS
|
|
|
|
|
+ * @intel_dp: DP struct
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
void intel_edp_drrs_disable(struct intel_dp *intel_dp)
|
|
void intel_edp_drrs_disable(struct intel_dp *intel_dp)
|
|
|
{
|
|
{
|
|
|
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
|
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
|
@@ -4929,6 +4952,17 @@ unlock:
|
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * intel_edp_drrs_invalidate - Invalidate DRRS
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ * @frontbuffer_bits: frontbuffer plane tracking bits
|
|
|
|
|
+ *
|
|
|
|
|
+ * When there is a disturbance on screen (due to cursor movement/time
|
|
|
|
|
+ * update etc), DRRS needs to be invalidated, i.e. need to switch to
|
|
|
|
|
+ * high RR.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
|
|
|
|
|
+ */
|
|
|
void intel_edp_drrs_invalidate(struct drm_device *dev,
|
|
void intel_edp_drrs_invalidate(struct drm_device *dev,
|
|
|
unsigned frontbuffer_bits)
|
|
unsigned frontbuffer_bits)
|
|
|
{
|
|
{
|
|
@@ -4956,6 +4990,17 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
|
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * intel_edp_drrs_flush - Flush DRRS
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ * @frontbuffer_bits: frontbuffer plane tracking bits
|
|
|
|
|
+ *
|
|
|
|
|
+ * When there is no movement on screen, DRRS work can be scheduled.
|
|
|
|
|
+ * This DRRS work is responsible for setting relevant registers after a
|
|
|
|
|
+ * timeout of 1 second.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
|
|
|
|
|
+ */
|
|
|
void intel_edp_drrs_flush(struct drm_device *dev,
|
|
void intel_edp_drrs_flush(struct drm_device *dev,
|
|
|
unsigned frontbuffer_bits)
|
|
unsigned frontbuffer_bits)
|
|
|
{
|
|
{
|
|
@@ -4980,6 +5025,56 @@ void intel_edp_drrs_flush(struct drm_device *dev,
|
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
mutex_unlock(&dev_priv->drrs.mutex);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * DOC: Display Refresh Rate Switching (DRRS)
|
|
|
|
|
+ *
|
|
|
|
|
+ * Display Refresh Rate Switching (DRRS) is a power conservation feature
|
|
|
|
|
+ * which enables swtching between low and high refresh rates,
|
|
|
|
|
+ * dynamically, based on the usage scenario. This feature is applicable
|
|
|
|
|
+ * for internal panels.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Indication that the panel supports DRRS is given by the panel EDID, which
|
|
|
|
|
+ * would list multiple refresh rates for one resolution.
|
|
|
|
|
+ *
|
|
|
|
|
+ * DRRS is of 2 types - static and seamless.
|
|
|
|
|
+ * Static DRRS involves changing refresh rate (RR) by doing a full modeset
|
|
|
|
|
+ * (may appear as a blink on screen) and is used in dock-undock scenario.
|
|
|
|
|
+ * Seamless DRRS involves changing RR without any visual effect to the user
|
|
|
|
|
+ * and can be used during normal system usage. This is done by programming
|
|
|
|
|
+ * certain registers.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Support for static/seamless DRRS may be indicated in the VBT based on
|
|
|
|
|
+ * inputs from the panel spec.
|
|
|
|
|
+ *
|
|
|
|
|
+ * DRRS saves power by switching to low RR based on usage scenarios.
|
|
|
|
|
+ *
|
|
|
|
|
+ * eDP DRRS:-
|
|
|
|
|
+ * The implementation is based on frontbuffer tracking implementation.
|
|
|
|
|
+ * When there is a disturbance on the screen triggered by user activity or a
|
|
|
|
|
+ * periodic system activity, DRRS is disabled (RR is changed to high RR).
|
|
|
|
|
+ * When there is no movement on screen, after a timeout of 1 second, a switch
|
|
|
|
|
+ * to low RR is made.
|
|
|
|
|
+ * For integration with frontbuffer tracking code,
|
|
|
|
|
+ * intel_edp_drrs_invalidate() and intel_edp_drrs_flush() are called.
|
|
|
|
|
+ *
|
|
|
|
|
+ * DRRS can be further extended to support other internal panels and also
|
|
|
|
|
+ * the scenario of video playback wherein RR is set based on the rate
|
|
|
|
|
+ * requested by userspace.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * intel_dp_drrs_init - Init basic DRRS work and mutex.
|
|
|
|
|
+ * @intel_connector: eDP connector
|
|
|
|
|
+ * @fixed_mode: preferred mode of panel
|
|
|
|
|
+ *
|
|
|
|
|
+ * This function is called only once at driver load to initialize basic
|
|
|
|
|
+ * DRRS stuff.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returns:
|
|
|
|
|
+ * Downclock mode if panel supports it, else return NULL.
|
|
|
|
|
+ * DRRS support is determined by the presence of downclock mode (apart
|
|
|
|
|
+ * from VBT setting).
|
|
|
|
|
+ */
|
|
|
static struct drm_display_mode *
|
|
static struct drm_display_mode *
|
|
|
intel_dp_drrs_init(struct intel_connector *intel_connector,
|
|
intel_dp_drrs_init(struct intel_connector *intel_connector,
|
|
|
struct drm_display_mode *fixed_mode)
|
|
struct drm_display_mode *fixed_mode)
|