@@ -39,6 +39,7 @@
#include "i915_trace.h"
#include <drm/drm_dp_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_rect.h>
#include <linux/dma_remapping.h>
static void intel_increase_pllclock(struct drm_crtc *crtc);
@@ -10280,19 +10281,144 @@ static void intel_shared_dpll_init(struct drm_device *dev)
BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
}
+static int
+intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_framebuffer *tmpfb;
+ struct drm_rect dest = {
+ .x1 = crtc_x,
+ .y1 = crtc_y,
+ .x2 = crtc_x + crtc_w,
+ .y2 = crtc_y + crtc_h,
+ };
+ struct drm_rect clip = {
+ .x2 = crtc->mode.hdisplay,
+ .y2 = crtc->mode.vdisplay,
+ };
+ int ret;
+
+ /* setplane API takes shifted source rectangle values; unshift them */
+ src_x >>= 16;
+ src_y >>= 16;
+ src_w >>= 16;
+ src_h >>= 16;
+
+ /*
+ * Current hardware can't reposition the primary plane or scale it
+ * (although this could change in the future).
+ */
+ drm_rect_intersect(&dest, &clip);
+ if (dest.x1 != 0 || dest.y1 != 0 ||
+ dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) {
+ DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n");
+ return -EINVAL;
+ }
+
+ if (crtc_w != src_w || crtc_h != src_h) {
+ DRM_DEBUG_KMS("Can't scale primary plane\n");
+ return -EINVAL;
+ }
+
+ /*
+ * pipe_set_base() adjusts crtc->primary->fb; however the DRM setplane
+ * code that called us expects to handle the framebuffer update and
+ * reference counting; save and restore the current fb before
+ * calling it.
+ */
+ tmpfb = plane->fb;
+ ret = intel_pipe_set_base(crtc, src_x, src_y, fb);
+ if (ret)
+ return ret;
+ plane->fb = tmpfb;
+
+ if (!intel_crtc->primary_enabled)
+ intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
+ intel_crtc->pipe);
+
+ return 0;
+}
+
+static int
+intel_primary_plane_disable(struct drm_plane *plane)
+{
+ struct drm_device *dev = plane->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct intel_crtc *intel_crtc;
+
+ if (!plane->fb)
+ return 0;
+
+ if (WARN_ON(!plane->crtc))
+ return -EINVAL;
+
+ intel_crtc = to_intel_crtc(plane->crtc);
+ if (intel_crtc->primary_enabled)
+ intel_disable_primary_hw_plane(dev_priv, intel_plane->plane,
+ intel_plane->pipe);
+
+ return 0;
+}
+
+static void intel_primary_plane_destroy(struct drm_plane *plane)
+{
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ intel_primary_plane_disable(plane);
+ drm_plane_cleanup(plane);
+ kfree(intel_plane);
+}
+
+static const struct drm_plane_funcs intel_primary_plane_funcs = {
+ .update_plane = intel_primary_plane_setplane,
+ .disable_plane = intel_primary_plane_disable,
+ .destroy = intel_primary_plane_destroy,
+};
+
+static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
+ int pipe)
+{
+ struct intel_plane *primary;
+
+ primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+ if (primary == NULL)
+ return NULL;
+
+ primary->can_scale = false;
+ primary->pipe = pipe;
+ primary->plane = pipe;
+
+ drm_plane_init(dev, &primary->base, 0,
+ &intel_primary_plane_funcs, legacy_modeset_formats,
+ ARRAY_SIZE(legacy_modeset_formats),
+ DRM_PLANE_TYPE_PRIMARY);
+ return &primary->base;
+}
+
static void intel_crtc_init(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc;
struct drm_plane *primary;
- int i;
+ int i, ret;
intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
if (intel_crtc == NULL)
return;
- primary = drm_primary_helper_create_plane(dev);
- drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
+ primary = intel_primary_plane_create(dev, pipe);
+ ret = drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
+ if (ret) {
+ drm_crtc_cleanup(&intel_crtc->base);
+ kfree(intel_crtc);
+ return;
+ }
drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
for (i = 0; i < 256; i++) {
@@ -348,6 +348,7 @@ struct intel_crtc {
bool active;
unsigned long enabled_power_domains;
bool eld_vld;
+ struct intel_plane *primary_plane;
bool primary_enabled; /* is the primary plane (partially) visible? */
bool lowfreq_avail;
struct intel_overlay *overlay;
Intel hardware allows the primary plane to be disabled independently of the CRTC. Provide custom primary plane handling to allow this. Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org> Signed-off-by: Matt Roper <matthew.d.roper@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 132 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 130 insertions(+), 3 deletions(-)