@@ -2516,6 +2516,7 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
+extern int i915_set_plane_zorder(struct drm_crtc *crtc, uint64_t zorder);
/* overlay */
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
@@ -3881,6 +3881,9 @@ enum punit_power_well {
#define SPRITE_INT_GAMMA_ENABLE (1<<13)
#define SPRITE_TILED (1<<10)
#define SPRITE_DEST_KEY (1<<2)
+#define SPRITE_FORCE_BOTTOM (1<<2)
+#define SPRITE_ZORDER_ENABLE (1<<0)
+
#define _SPRA_LINOFF 0x70284
#define _SPRA_STRIDE 0x70288
#define _SPRA_POS 0x7028c
@@ -2169,18 +2169,27 @@ static int i9xx_update_primary_plane(struct drm_crtc *crtc,
break;
case DRM_FORMAT_XRGB1555:
case DRM_FORMAT_ARGB1555:
- dspcntr |= DISPPLANE_BGRX555;
+ if (intel_crtc->primary_alpha)
+ dspcntr |= DISPPLANE_BGRA555;
+ else
+ dspcntr |= DISPPLANE_BGRX555;
break;
case DRM_FORMAT_RGB565:
dspcntr |= DISPPLANE_BGRX565;
break;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
- dspcntr |= DISPPLANE_BGRX888;
+ if (intel_crtc->primary_alpha)
+ dspcntr |= DISPPLANE_BGRA888;
+ else
+ dspcntr |= DISPPLANE_BGRX888;
break;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
- dspcntr |= DISPPLANE_RGBX888;
+ if (intel_crtc->primary_alpha)
+ dspcntr |= DISPPLANE_RGBA888;
+ else
+ dspcntr |= DISPPLANE_RGBX888;
break;
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
@@ -2188,7 +2197,10 @@ static int i9xx_update_primary_plane(struct drm_crtc *crtc,
break;
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ABGR2101010:
- dspcntr |= DISPPLANE_RGBX101010;
+ if (intel_crtc->primary_alpha)
+ dspcntr |= DISPPLANE_RGBA101010;
+ else
+ dspcntr |= DISPPLANE_RGBX101010;
break;
default:
BUG();
@@ -8470,6 +8482,9 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
intel_crtc_cursor_set(crtc, NULL, 0, 0, 0);
+ if (intel_crtc->zorder_property)
+ drm_property_destroy(dev, intel_crtc->zorder_property);
+
drm_crtc_cleanup(crtc);
kfree(intel_crtc);
@@ -10422,6 +10437,27 @@ out_config:
return ret;
}
+static int intel_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_property *prop,
+ uint64_t val)
+{
+ struct intel_crtc *icrtc = to_intel_crtc(crtc);
+ int ret = -ENOENT;
+
+ if (prop && prop == icrtc->zorder_property) {
+ /* Simply return if no change in zorder */
+ if (icrtc->zorder == val)
+ return 0;
+
+ ret = i915_set_plane_zorder(crtc, val);
+
+ if (!ret)
+ icrtc->zorder = val;
+ }
+
+ return ret;
+}
+
static const struct drm_crtc_funcs intel_crtc_funcs = {
.cursor_set = intel_crtc_cursor_set,
.cursor_move = intel_crtc_cursor_move,
@@ -10429,6 +10465,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.set_config = intel_crtc_set_config,
.destroy = intel_crtc_destroy,
.page_flip = intel_crtc_page_flip,
+ .set_property = intel_crtc_set_property,
};
static void intel_cpu_pll_init(struct drm_device *dev)
@@ -10536,6 +10573,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc;
+ struct drm_property *prop = 0;
int i;
intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
@@ -10568,6 +10606,18 @@ 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);
+
+ intel_crtc->primary_alpha = false;
+ intel_crtc->sprite0_alpha = true;
+ intel_crtc->sprite1_alpha = true;
+
+ if (IS_VALLEYVIEW(dev))
+ prop = drm_property_create(dev, 0, "zorder", 1);
+
+ if (prop)
+ drm_object_attach_property(&intel_crtc->base.base, prop, 0);
+
+ intel_crtc->zorder_property = prop;
}
enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
@@ -387,6 +387,9 @@ struct intel_crtc {
bool new_enabled;
uint32_t ddi_pll_sel;
+ bool primary_alpha;
+ bool sprite0_alpha;
+ bool sprite1_alpha;
/* reset counter value when the last flip was submitted */
unsigned int reset_counter;
@@ -400,6 +403,9 @@ struct intel_crtc {
/* watermarks currently being used */
struct intel_pipe_wm active;
} wm;
+
+ struct drm_property *zorder_property;
+ uint64_t zorder;
};
struct intel_plane_wm_parameters {
@@ -37,6 +37,101 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
+static int vlv_set_plane_zorder(struct drm_crtc *crtc, uint64_t order)
+{
+ struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+ u32 val;
+ int s1_zorder = 0, s1_bottom = 0, s2_zorder = 0, s2_bottom = 0;
+ unsigned int i, z_order[I915_PLANE_MAX_NUM];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+
+ /* Get plane order from bottom (lower bits) to top (higher bits) */
+ for (i = 0; i < I915_PLANE_MAX_NUM; i++)
+ z_order[i] = (order >> (i*4)) & 0xF;
+
+ /* The top layer must be cursor */
+ if (z_order[i-1] != I915_PLANE_CURSOR)
+ return -EINVAL;
+
+ /* No duplicated setting */
+ if (z_order[0] == z_order[1] ||
+ z_order[0] == z_order[2] ||
+ z_order[1] == z_order[2])
+ return -EINVAL;
+
+ switch (z_order[0]) {
+ case I915_PLANE_PRIMARY:
+ if (z_order[1] == I915_PLANE_SPRITE_B)
+ s1_zorder = 1;
+ break;
+ case I915_PLANE_SPRITE_A:
+ s1_bottom = 1;
+ if (z_order[1] == I915_PLANE_SPRITE_B)
+ s2_zorder = 1;
+ break;
+ case I915_PLANE_SPRITE_B:
+ s2_bottom = 1;
+ if (z_order[1] == I915_PLANE_SPRITE_A)
+ s1_zorder = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Clear the older Z-order */
+ val = I915_READ(SPCNTR(pipe, 0));
+ val &= ~(SPRITE_FORCE_BOTTOM | SPRITE_ZORDER_ENABLE);
+ I915_WRITE(SPCNTR(pipe, 0), val);
+
+ val = I915_READ(SPCNTR(pipe, 1));
+ val &= ~(SPRITE_FORCE_BOTTOM | SPRITE_ZORDER_ENABLE);
+ I915_WRITE(SPCNTR(pipe, 1), val);
+
+ /* Program new Z-order */
+ val = I915_READ(SPCNTR(pipe, 0));
+ if (s1_zorder)
+ val |= SPRITE_ZORDER_ENABLE;
+ if (s1_bottom)
+ val |= SPRITE_FORCE_BOTTOM;
+ I915_WRITE(SPCNTR(pipe, 0), val);
+
+ val = I915_READ(SPCNTR(pipe, 1));
+ if (s2_zorder)
+ val |= SPRITE_ZORDER_ENABLE;
+ if (s2_bottom)
+ val |= SPRITE_FORCE_BOTTOM;
+ I915_WRITE(SPCNTR(pipe, 1), val);
+
+ /* If a plane is not at bottom, the alpha channel should be on. */
+ if (z_order[0] != I915_PLANE_PRIMARY)
+ intel_crtc->primary_alpha = true;
+ else
+ intel_crtc->primary_alpha = false;
+
+ if (z_order[0] != I915_PLANE_SPRITE_A)
+ intel_crtc->sprite0_alpha = true;
+ else
+ intel_crtc->sprite0_alpha = false;
+
+ if (z_order[0] != I915_PLANE_SPRITE_B)
+ intel_crtc->sprite1_alpha = true;
+ else
+ intel_crtc->sprite1_alpha = false;
+
+ return 0;
+}
+
+int i915_set_plane_zorder(struct drm_crtc *crtc, uint64_t val)
+{
+ int ret = -ENOENT;
+
+ if (IS_VALLEYVIEW(crtc->dev))
+ ret = vlv_set_plane_zorder(crtc, val);
+
+ return ret;
+}
+
static void
vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
struct drm_framebuffer *fb,
@@ -50,10 +145,19 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
struct intel_plane *intel_plane = to_intel_plane(dplane);
int pipe = intel_plane->pipe;
int plane = intel_plane->plane;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 sprctl;
+ bool alpha = true;
unsigned long sprsurf_offset, linear_offset;
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+ if (plane && intel_crtc->sprite1_alpha)
+ alpha = true;
+ else if (!plane && intel_crtc->sprite0_alpha)
+ alpha = true;
+ else
+ alpha = false;
+
sprctl = I915_READ(SPCNTR(pipe, plane));
/* Mask out pixel format bits in case we change it */
@@ -81,19 +185,28 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
sprctl |= SP_FORMAT_BGRX8888;
break;
case DRM_FORMAT_ARGB8888:
- sprctl |= SP_FORMAT_BGRA8888;
+ if (alpha)
+ sprctl |= SP_FORMAT_BGRA8888;
+ else
+ sprctl |= SP_FORMAT_BGRX8888;
break;
case DRM_FORMAT_XBGR2101010:
sprctl |= SP_FORMAT_RGBX1010102;
break;
case DRM_FORMAT_ABGR2101010:
- sprctl |= SP_FORMAT_RGBA1010102;
+ if (alpha)
+ sprctl |= SP_FORMAT_RGBA1010102;
+ else
+ sprctl |= SP_FORMAT_RGBX1010102;
break;
case DRM_FORMAT_XBGR8888:
sprctl |= SP_FORMAT_RGBX8888;
break;
case DRM_FORMAT_ABGR8888:
- sprctl |= SP_FORMAT_RGBA8888;
+ if (alpha)
+ sprctl |= SP_FORMAT_RGBA8888;
+ else
+ sprctl |= SP_FORMAT_RGBX8888;
break;
default:
/*
@@ -1050,4 +1050,10 @@ struct drm_i915_reset_stats {
__u32 pad;
};
+#define I915_PLANE_PRIMARY 0
+#define I915_PLANE_SPRITE_A 1
+#define I915_PLANE_SPRITE_B 2
+#define I915_PLANE_CURSOR 3
+#define I915_PLANE_MAX_NUM (I915_PLANE_CURSOR + 1)
+
#endif /* _UAPI_I915_DRM_H_ */