@@ -1608,6 +1608,12 @@ typedef struct drm_i915_private {
struct drm_property *broadcast_rgb_property;
struct drm_property *force_audio_property;
+ /*
+ * Property to dynamically vary the size of the
+ * PIPESRC or Panel fitter input size
+ */
+ struct drm_property *input_size_property;
+
uint32_t hw_context_size;
struct list_head context_list;
@@ -8935,8 +8935,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
* Note that pitch changes could also affect these register.
*/
if (INTEL_INFO(dev)->gen > 3 &&
- (fb->offsets[0] != crtc->fb->offsets[0] ||
- fb->pitches[0] != crtc->fb->pitches[0]))
+ (fb->offsets[0] != crtc->fb->offsets[0]))
+ return -EINVAL;
+
+ /*
+ * Bypassing the fb pitch check for VLV/HSW, as purportedly there
+ * is a dynamic flip support in VLV/HSW. This will allow to
+ * flip fbs of different resolutions without doing a modeset.
+ * TBD, confirm the same for other newer gen platforms also.
+ */
+ if (INTEL_INFO(dev)->gen > 3 &&
+ !IS_VALLEYVIEW(dev) && !IS_HASWELL(dev) &&
+ (fb->pitches[0] != crtc->fb->pitches[0]))
return -EINVAL;
if (i915_terminally_wedged(&dev_priv->gpu_error))
@@ -10434,8 +10444,50 @@ out_config:
static int intel_crtc_set_property(struct drm_crtc *crtc,
struct drm_property *property, uint64_t val)
{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int ret = -ENOENT;
+ if (property == dev_priv->input_size_property) {
+ int new_width = (int)((val >> 16) & 0xffff);
+ int new_height = (int)(val & 0xffff);
+ const struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+
+ if ((new_width == intel_crtc->config.pipe_src_w) &&
+ (new_height == intel_crtc->config.pipe_src_h))
+ return 0;
+
+ if (((adjusted_mode->crtc_hdisplay != new_width) ||
+ (adjusted_mode->crtc_vdisplay != new_height)) &&
+ ((HAS_PCH_SPLIT(dev) &&
+ (!intel_crtc->config.pch_pfit.enabled)) ||
+ (!HAS_PCH_SPLIT(dev) &&
+ (!intel_crtc->config.gmch_pfit.control)))) {
+ DRM_ERROR("PIPESRC mismatch with Pipe timings & PF is disabled\n");
+ return -EINVAL;
+ }
+
+ intel_crtc->config.pipe_src_w = new_width;
+ intel_crtc->config.pipe_src_h = new_height;
+
+ intel_crtc->config.requested_mode.hdisplay = new_width;
+ intel_crtc->config.requested_mode.vdisplay = new_height;
+
+ crtc->mode.hdisplay = new_width;
+ crtc->mode.vdisplay = new_height;
+
+ /* pipesrc controls the size that is scaled from, which should
+ * always be the user's requested size.
+ */
+ I915_WRITE(PIPESRC(intel_crtc->pipe),
+ ((intel_crtc->config.pipe_src_w - 1) << 16) |
+ (intel_crtc->config.pipe_src_h - 1));
+
+ return 0;
+ }
+
return ret;
}
@@ -10586,6 +10638,15 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+
+ if (!dev_priv->input_size_property)
+ dev_priv->input_size_property =
+ drm_property_create_range(dev, 0, "input size", 0, 0xFFFFFFFF);
+
+ if (dev_priv->input_size_property)
+ drm_object_attach_property(&intel_crtc->base.base,
+ dev_priv->input_size_property,
+ 0);
}
enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)