aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-12-13 16:19:38 -0500
committerKeith Packard <keithp@keithp.com>2012-01-03 12:31:09 -0500
commitb840d907fcf6d5d5ef91af4518b3dab3a5da0f75 (patch)
treeaea5477428533760383870a39e7768bd8f59567d /drivers/gpu
parentc7dffff7cc8de748edf0e9f6571cdabecb198705 (diff)
drm/i915: add SNB and IVB video sprite support v6
The video sprites support various video surface formats natively and can handle scaling as well. So add support for them using the new DRM core sprite support functions. v2: use drm specific fourcc header and defines v3: address Daniel's comments: - don't take struct mutex around register access (only needed for regs in the GT power well) - don't hold struct mutex across vblank waits - fix up update_plane API (pass obj instead of GTT offset) - add interlaced defines for sprite regs - drop unnecessary 'reg' variables - comment double buffered reg flushing Also fix w/h confusion when writing the scaling reg. v4: more fixes, address more comments from Daniel, and include Hai's fix - prevent divide by zero in scaling calculation (Hai Lan) - update to Ville's new DRM_FORMAT_* types - fix sprite watermark handling (calc based on CRTC size, separate from normal display wm) - remove private refcounts now that the fb cleanups handles things v5: add linear surface support v6: remove color key clearing & setting from update_plane For this version, I tested DPMS since it came up in the last review; DPMS off/on works ok when a video player is working under X, but for power saving we'll probably want to do something smarter. I'll leave that for a separate patch on top. Likewise with the refcounting/fb layer handling, which are really separate cleanups. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h3
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h133
-rw-r--r--drivers/gpu/drm/i915/intel_display.c174
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h28
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c6
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c450
7 files changed, 788 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0ae6a7c5020f..808b255d7fc6 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -28,6 +28,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
28 intel_dvo.o \ 28 intel_dvo.o \
29 intel_ringbuffer.o \ 29 intel_ringbuffer.o \
30 intel_overlay.o \ 30 intel_overlay.o \
31 intel_sprite.o \
31 intel_opregion.o \ 32 intel_opregion.o \
32 dvo_ch7xxx.o \ 33 dvo_ch7xxx.o \
33 dvo_ch7017.o \ 34 dvo_ch7017.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 621840c05f0c..602bc80baabb 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -207,6 +207,8 @@ struct drm_i915_display_funcs {
207 int (*get_display_clock_speed)(struct drm_device *dev); 207 int (*get_display_clock_speed)(struct drm_device *dev);
208 int (*get_fifo_size)(struct drm_device *dev, int plane); 208 int (*get_fifo_size)(struct drm_device *dev, int plane);
209 void (*update_wm)(struct drm_device *dev); 209 void (*update_wm)(struct drm_device *dev);
210 void (*update_sprite_wm)(struct drm_device *dev, int pipe,
211 uint32_t sprite_width, int pixel_size);
210 int (*crtc_mode_set)(struct drm_crtc *crtc, 212 int (*crtc_mode_set)(struct drm_crtc *crtc,
211 struct drm_display_mode *mode, 213 struct drm_display_mode *mode,
212 struct drm_display_mode *adjusted_mode, 214 struct drm_display_mode *adjusted_mode,
@@ -352,6 +354,7 @@ typedef struct drm_i915_private {
352 354
353 /* overlay */ 355 /* overlay */
354 struct intel_overlay *overlay; 356 struct intel_overlay *overlay;
357 bool sprite_scaling_enabled;
355 358
356 /* LVDS info */ 359 /* LVDS info */
357 int backlight_level; /* restore backlight to this value */ 360 int backlight_level; /* restore backlight to this value */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 44eabb088b48..d791043c8ec1 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2461,6 +2461,8 @@
2461#define WM3_LP_ILK 0x45110 2461#define WM3_LP_ILK 0x45110
2462#define WM3_LP_EN (1<<31) 2462#define WM3_LP_EN (1<<31)
2463#define WM1S_LP_ILK 0x45120 2463#define WM1S_LP_ILK 0x45120
2464#define WM2S_LP_IVB 0x45124
2465#define WM3S_LP_IVB 0x45128
2464#define WM1S_LP_EN (1<<31) 2466#define WM1S_LP_EN (1<<31)
2465 2467
2466/* Memory latency timer register */ 2468/* Memory latency timer register */
@@ -2677,6 +2679,137 @@
2677#define _DSPBSURF 0x7119C 2679#define _DSPBSURF 0x7119C
2678#define _DSPBTILEOFF 0x711A4 2680#define _DSPBTILEOFF 0x711A4
2679 2681
2682/* Sprite A control */
2683#define _DVSACNTR 0x72180
2684#define DVS_ENABLE (1<<31)
2685#define DVS_GAMMA_ENABLE (1<<30)
2686#define DVS_PIXFORMAT_MASK (3<<25)
2687#define DVS_FORMAT_YUV422 (0<<25)
2688#define DVS_FORMAT_RGBX101010 (1<<25)
2689#define DVS_FORMAT_RGBX888 (2<<25)
2690#define DVS_FORMAT_RGBX161616 (3<<25)
2691#define DVS_SOURCE_KEY (1<<22)
2692#define DVS_RGB_ORDER_RGBX (1<<20)
2693#define DVS_YUV_BYTE_ORDER_MASK (3<<16)
2694#define DVS_YUV_ORDER_YUYV (0<<16)
2695#define DVS_YUV_ORDER_UYVY (1<<16)
2696#define DVS_YUV_ORDER_YVYU (2<<16)
2697#define DVS_YUV_ORDER_VYUY (3<<16)
2698#define DVS_DEST_KEY (1<<2)
2699#define DVS_TRICKLE_FEED_DISABLE (1<<14)
2700#define DVS_TILED (1<<10)
2701#define _DVSALINOFF 0x72184
2702#define _DVSASTRIDE 0x72188
2703#define _DVSAPOS 0x7218c
2704#define _DVSASIZE 0x72190
2705#define _DVSAKEYVAL 0x72194
2706#define _DVSAKEYMSK 0x72198
2707#define _DVSASURF 0x7219c
2708#define _DVSAKEYMAXVAL 0x721a0
2709#define _DVSATILEOFF 0x721a4
2710#define _DVSASURFLIVE 0x721ac
2711#define _DVSASCALE 0x72204
2712#define DVS_SCALE_ENABLE (1<<31)
2713#define DVS_FILTER_MASK (3<<29)
2714#define DVS_FILTER_MEDIUM (0<<29)
2715#define DVS_FILTER_ENHANCING (1<<29)
2716#define DVS_FILTER_SOFTENING (2<<29)
2717#define DVS_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */
2718#define DVS_VERTICAL_OFFSET_ENABLE (1<<27)
2719#define _DVSAGAMC 0x72300
2720
2721#define _DVSBCNTR 0x73180
2722#define _DVSBLINOFF 0x73184
2723#define _DVSBSTRIDE 0x73188
2724#define _DVSBPOS 0x7318c
2725#define _DVSBSIZE 0x73190
2726#define _DVSBKEYVAL 0x73194
2727#define _DVSBKEYMSK 0x73198
2728#define _DVSBSURF 0x7319c
2729#define _DVSBKEYMAXVAL 0x731a0
2730#define _DVSBTILEOFF 0x731a4
2731#define _DVSBSURFLIVE 0x731ac
2732#define _DVSBSCALE 0x73204
2733#define _DVSBGAMC 0x73300
2734
2735#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR)
2736#define DVSLINOFF(pipe) _PIPE(pipe, _DVSALINOFF, _DVSBLINOFF)
2737#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
2738#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS)
2739#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF)
2740#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE)
2741#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE)
2742#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
2743
2744#define _SPRA_CTL 0x70280
2745#define SPRITE_ENABLE (1<<31)
2746#define SPRITE_GAMMA_ENABLE (1<<30)
2747#define SPRITE_PIXFORMAT_MASK (7<<25)
2748#define SPRITE_FORMAT_YUV422 (0<<25)
2749#define SPRITE_FORMAT_RGBX101010 (1<<25)
2750#define SPRITE_FORMAT_RGBX888 (2<<25)
2751#define SPRITE_FORMAT_RGBX161616 (3<<25)
2752#define SPRITE_FORMAT_YUV444 (4<<25)
2753#define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */
2754#define SPRITE_CSC_ENABLE (1<<24)
2755#define SPRITE_SOURCE_KEY (1<<22)
2756#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */
2757#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19)
2758#define SPRITE_YUV_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */
2759#define SPRITE_YUV_BYTE_ORDER_MASK (3<<16)
2760#define SPRITE_YUV_ORDER_YUYV (0<<16)
2761#define SPRITE_YUV_ORDER_UYVY (1<<16)
2762#define SPRITE_YUV_ORDER_YVYU (2<<16)
2763#define SPRITE_YUV_ORDER_VYUY (3<<16)
2764#define SPRITE_TRICKLE_FEED_DISABLE (1<<14)
2765#define SPRITE_INT_GAMMA_ENABLE (1<<13)
2766#define SPRITE_TILED (1<<10)
2767#define SPRITE_DEST_KEY (1<<2)
2768#define _SPRA_LINOFF 0x70284
2769#define _SPRA_STRIDE 0x70288
2770#define _SPRA_POS 0x7028c
2771#define _SPRA_SIZE 0x70290
2772#define _SPRA_KEYVAL 0x70294
2773#define _SPRA_KEYMSK 0x70298
2774#define _SPRA_SURF 0x7029c
2775#define _SPRA_KEYMAX 0x702a0
2776#define _SPRA_TILEOFF 0x702a4
2777#define _SPRA_SCALE 0x70304
2778#define SPRITE_SCALE_ENABLE (1<<31)
2779#define SPRITE_FILTER_MASK (3<<29)
2780#define SPRITE_FILTER_MEDIUM (0<<29)
2781#define SPRITE_FILTER_ENHANCING (1<<29)
2782#define SPRITE_FILTER_SOFTENING (2<<29)
2783#define SPRITE_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */
2784#define SPRITE_VERTICAL_OFFSET_ENABLE (1<<27)
2785#define _SPRA_GAMC 0x70400
2786
2787#define _SPRB_CTL 0x71280
2788#define _SPRB_LINOFF 0x71284
2789#define _SPRB_STRIDE 0x71288
2790#define _SPRB_POS 0x7128c
2791#define _SPRB_SIZE 0x71290
2792#define _SPRB_KEYVAL 0x71294
2793#define _SPRB_KEYMSK 0x71298
2794#define _SPRB_SURF 0x7129c
2795#define _SPRB_KEYMAX 0x712a0
2796#define _SPRB_TILEOFF 0x712a4
2797#define _SPRB_SCALE 0x71304
2798#define _SPRB_GAMC 0x71400
2799
2800#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
2801#define SPRLINOFF(pipe) _PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF)
2802#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE)
2803#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS)
2804#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE)
2805#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL)
2806#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK)
2807#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
2808#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX)
2809#define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF)
2810#define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE)
2811#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
2812
2680/* VBIOS regs */ 2813/* VBIOS regs */
2681#define VGACNTRL 0x71400 2814#define VGACNTRL 0x71400
2682# define VGA_DISP_DISABLE (1 << 31) 2815# define VGA_DISP_DISABLE (1 << 31)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ff99fa267bf6..30397b74a4a3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -915,8 +915,8 @@ static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
915 pipe_name(pipe)); 915 pipe_name(pipe));
916} 916}
917 917
918static void assert_pipe(struct drm_i915_private *dev_priv, 918void assert_pipe(struct drm_i915_private *dev_priv,
919 enum pipe pipe, bool state) 919 enum pipe pipe, bool state)
920{ 920{
921 int reg; 921 int reg;
922 u32 val; 922 u32 val;
@@ -929,8 +929,6 @@ static void assert_pipe(struct drm_i915_private *dev_priv,
929 "pipe %c assertion failure (expected %s, current %s)\n", 929 "pipe %c assertion failure (expected %s, current %s)\n",
930 pipe_name(pipe), state_string(state), state_string(cur_state)); 930 pipe_name(pipe), state_string(state), state_string(cur_state));
931} 931}
932#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
933#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
934 932
935static void assert_plane_enabled(struct drm_i915_private *dev_priv, 933static void assert_plane_enabled(struct drm_i915_private *dev_priv,
936 enum plane plane) 934 enum plane plane)
@@ -4509,7 +4507,7 @@ static void ironlake_update_wm(struct drm_device *dev)
4509 */ 4507 */
4510} 4508}
4511 4509
4512static void sandybridge_update_wm(struct drm_device *dev) 4510void sandybridge_update_wm(struct drm_device *dev)
4513{ 4511{
4514 struct drm_i915_private *dev_priv = dev->dev_private; 4512 struct drm_i915_private *dev_priv = dev->dev_private;
4515 int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ 4513 int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
@@ -4569,7 +4567,8 @@ static void sandybridge_update_wm(struct drm_device *dev)
4569 I915_WRITE(WM2_LP_ILK, 0); 4567 I915_WRITE(WM2_LP_ILK, 0);
4570 I915_WRITE(WM1_LP_ILK, 0); 4568 I915_WRITE(WM1_LP_ILK, 0);
4571 4569
4572 if (!single_plane_enabled(enabled)) 4570 if (!single_plane_enabled(enabled) ||
4571 dev_priv->sprite_scaling_enabled)
4573 return; 4572 return;
4574 enabled = ffs(enabled) - 1; 4573 enabled = ffs(enabled) - 1;
4575 4574
@@ -4619,6 +4618,149 @@ static void sandybridge_update_wm(struct drm_device *dev)
4619 cursor_wm); 4618 cursor_wm);
4620} 4619}
4621 4620
4621static bool
4622sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
4623 uint32_t sprite_width, int pixel_size,
4624 const struct intel_watermark_params *display,
4625 int display_latency_ns, int *sprite_wm)
4626{
4627 struct drm_crtc *crtc;
4628 int clock;
4629 int entries, tlb_miss;
4630
4631 crtc = intel_get_crtc_for_plane(dev, plane);
4632 if (crtc->fb == NULL || !crtc->enabled) {
4633 *sprite_wm = display->guard_size;
4634 return false;
4635 }
4636
4637 clock = crtc->mode.clock;
4638
4639 /* Use the small buffer method to calculate the sprite watermark */
4640 entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
4641 tlb_miss = display->fifo_size*display->cacheline_size -
4642 sprite_width * 8;
4643 if (tlb_miss > 0)
4644 entries += tlb_miss;
4645 entries = DIV_ROUND_UP(entries, display->cacheline_size);
4646 *sprite_wm = entries + display->guard_size;
4647 if (*sprite_wm > (int)display->max_wm)
4648 *sprite_wm = display->max_wm;
4649
4650 return true;
4651}
4652
4653static bool
4654sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
4655 uint32_t sprite_width, int pixel_size,
4656 const struct intel_watermark_params *display,
4657 int latency_ns, int *sprite_wm)
4658{
4659 struct drm_crtc *crtc;
4660 unsigned long line_time_us;
4661 int clock;
4662 int line_count, line_size;
4663 int small, large;
4664 int entries;
4665
4666 if (!latency_ns) {
4667 *sprite_wm = 0;
4668 return false;
4669 }
4670
4671 crtc = intel_get_crtc_for_plane(dev, plane);
4672 clock = crtc->mode.clock;
4673
4674 line_time_us = (sprite_width * 1000) / clock;
4675 line_count = (latency_ns / line_time_us + 1000) / 1000;
4676 line_size = sprite_width * pixel_size;
4677
4678 /* Use the minimum of the small and large buffer method for primary */
4679 small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
4680 large = line_count * line_size;
4681
4682 entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
4683 *sprite_wm = entries + display->guard_size;
4684
4685 return *sprite_wm > 0x3ff ? false : true;
4686}
4687
4688static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
4689 uint32_t sprite_width, int pixel_size)
4690{
4691 struct drm_i915_private *dev_priv = dev->dev_private;
4692 int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
4693 int sprite_wm, reg;
4694 int ret;
4695
4696 switch (pipe) {
4697 case 0:
4698 reg = WM0_PIPEA_ILK;
4699 break;
4700 case 1:
4701 reg = WM0_PIPEB_ILK;
4702 break;
4703 case 2:
4704 reg = WM0_PIPEC_IVB;
4705 break;
4706 default:
4707 return; /* bad pipe */
4708 }
4709
4710 ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size,
4711 &sandybridge_display_wm_info,
4712 latency, &sprite_wm);
4713 if (!ret) {
4714 DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n",
4715 pipe);
4716 return;
4717 }
4718
4719 I915_WRITE(reg, I915_READ(reg) | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
4720 DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
4721
4722
4723 ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
4724 pixel_size,
4725 &sandybridge_display_srwm_info,
4726 SNB_READ_WM1_LATENCY() * 500,
4727 &sprite_wm);
4728 if (!ret) {
4729 DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n",
4730 pipe);
4731 return;
4732 }
4733 I915_WRITE(WM1S_LP_ILK, sprite_wm);
4734
4735 /* Only IVB has two more LP watermarks for sprite */
4736 if (!IS_IVYBRIDGE(dev))
4737 return;
4738
4739 ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
4740 pixel_size,
4741 &sandybridge_display_srwm_info,
4742 SNB_READ_WM2_LATENCY() * 500,
4743 &sprite_wm);
4744 if (!ret) {
4745 DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n",
4746 pipe);
4747 return;
4748 }
4749 I915_WRITE(WM2S_LP_IVB, sprite_wm);
4750
4751 ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
4752 pixel_size,
4753 &sandybridge_display_srwm_info,
4754 SNB_READ_WM3_LATENCY() * 500,
4755 &sprite_wm);
4756 if (!ret) {
4757 DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n",
4758 pipe);
4759 return;
4760 }
4761 I915_WRITE(WM3S_LP_IVB, sprite_wm);
4762}
4763
4622/** 4764/**
4623 * intel_update_watermarks - update FIFO watermark values based on current modes 4765 * intel_update_watermarks - update FIFO watermark values based on current modes
4624 * 4766 *
@@ -4659,6 +4801,16 @@ static void intel_update_watermarks(struct drm_device *dev)
4659 dev_priv->display.update_wm(dev); 4801 dev_priv->display.update_wm(dev);
4660} 4802}
4661 4803
4804void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
4805 uint32_t sprite_width, int pixel_size)
4806{
4807 struct drm_i915_private *dev_priv = dev->dev_private;
4808
4809 if (dev_priv->display.update_sprite_wm)
4810 dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
4811 pixel_size);
4812}
4813
4662static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) 4814static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
4663{ 4815{
4664 if (i915_panel_use_ssc >= 0) 4816 if (i915_panel_use_ssc >= 0)
@@ -8631,6 +8783,7 @@ static void intel_init_display(struct drm_device *dev)
8631 } else if (IS_GEN6(dev)) { 8783 } else if (IS_GEN6(dev)) {
8632 if (SNB_READ_WM0_LATENCY()) { 8784 if (SNB_READ_WM0_LATENCY()) {
8633 dev_priv->display.update_wm = sandybridge_update_wm; 8785 dev_priv->display.update_wm = sandybridge_update_wm;
8786 dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
8634 } else { 8787 } else {
8635 DRM_DEBUG_KMS("Failed to read display plane latency. " 8788 DRM_DEBUG_KMS("Failed to read display plane latency. "
8636 "Disable CxSR\n"); 8789 "Disable CxSR\n");
@@ -8644,6 +8797,7 @@ static void intel_init_display(struct drm_device *dev)
8644 dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; 8797 dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
8645 if (SNB_READ_WM0_LATENCY()) { 8798 if (SNB_READ_WM0_LATENCY()) {
8646 dev_priv->display.update_wm = sandybridge_update_wm; 8799 dev_priv->display.update_wm = sandybridge_update_wm;
8800 dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
8647 } else { 8801 } else {
8648 DRM_DEBUG_KMS("Failed to read display plane latency. " 8802 DRM_DEBUG_KMS("Failed to read display plane latency. "
8649 "Disable CxSR\n"); 8803 "Disable CxSR\n");
@@ -8827,7 +8981,7 @@ static void i915_disable_vga(struct drm_device *dev)
8827void intel_modeset_init(struct drm_device *dev) 8981void intel_modeset_init(struct drm_device *dev)
8828{ 8982{
8829 struct drm_i915_private *dev_priv = dev->dev_private; 8983 struct drm_i915_private *dev_priv = dev->dev_private;
8830 int i; 8984 int i, ret;
8831 8985
8832 drm_mode_config_init(dev); 8986 drm_mode_config_init(dev);
8833 8987
@@ -8857,6 +9011,12 @@ void intel_modeset_init(struct drm_device *dev)
8857 9011
8858 for (i = 0; i < dev_priv->num_pipe; i++) { 9012 for (i = 0; i < dev_priv->num_pipe; i++) {
8859 intel_crtc_init(dev, i); 9013 intel_crtc_init(dev, i);
9014 if (HAS_PCH_SPLIT(dev)) {
9015 ret = intel_plane_init(dev, i);
9016 if (ret)
9017 DRM_ERROR("plane %d init failed: %d\n",
9018 i, ret);
9019 }
8860 } 9020 }
8861 9021
8862 /* Just disable it once at startup */ 9022 /* Just disable it once at startup */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 82a459bfccbc..a6e2f0d865b1 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -177,10 +177,27 @@ struct intel_crtc {
177 bool use_pll_a; 177 bool use_pll_a;
178}; 178};
179 179
180struct intel_plane {
181 struct drm_plane base;
182 enum pipe pipe;
183 struct drm_i915_gem_object *obj;
184 int max_downscale;
185 u32 lut_r[1024], lut_g[1024], lut_b[1024];
186 void (*update_plane)(struct drm_plane *plane,
187 struct drm_framebuffer *fb,
188 struct drm_i915_gem_object *obj,
189 int crtc_x, int crtc_y,
190 unsigned int crtc_w, unsigned int crtc_h,
191 uint32_t x, uint32_t y,
192 uint32_t src_w, uint32_t src_h);
193 void (*disable_plane)(struct drm_plane *plane);
194};
195
180#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) 196#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
181#define to_intel_connector(x) container_of(x, struct intel_connector, base) 197#define to_intel_connector(x) container_of(x, struct intel_connector, base)
182#define to_intel_encoder(x) container_of(x, struct intel_encoder, base) 198#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
183#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) 199#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
200#define to_intel_plane(x) container_of(x, struct intel_plane, base)
184 201
185#define DIP_HEADER_SIZE 5 202#define DIP_HEADER_SIZE 5
186 203
@@ -290,6 +307,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
290extern bool intel_dpd_is_edp(struct drm_device *dev); 307extern bool intel_dpd_is_edp(struct drm_device *dev);
291extern void intel_edp_link_config(struct intel_encoder *, int *, int *); 308extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
292extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); 309extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
310extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
293 311
294/* intel_panel.c */ 312/* intel_panel.c */
295extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, 313extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
@@ -380,9 +398,19 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
380extern void intel_fb_output_poll_changed(struct drm_device *dev); 398extern void intel_fb_output_poll_changed(struct drm_device *dev);
381extern void intel_fb_restore_mode(struct drm_device *dev); 399extern void intel_fb_restore_mode(struct drm_device *dev);
382 400
401extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
402 bool state);
403#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
404#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
405
383extern void intel_init_clock_gating(struct drm_device *dev); 406extern void intel_init_clock_gating(struct drm_device *dev);
384extern void intel_write_eld(struct drm_encoder *encoder, 407extern void intel_write_eld(struct drm_encoder *encoder,
385 struct drm_display_mode *mode); 408 struct drm_display_mode *mode);
386extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); 409extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
387 410
411/* For use by IVB LP watermark workaround in intel_sprite.c */
412extern void sandybridge_update_wm(struct drm_device *dev);
413extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
414 uint32_t sprite_width,
415 int pixel_size);
388#endif /* __INTEL_DRV_H__ */ 416#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index f02fc71a57a5..571375a3eef4 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -270,8 +270,14 @@ void intel_fb_restore_mode(struct drm_device *dev)
270{ 270{
271 int ret; 271 int ret;
272 drm_i915_private_t *dev_priv = dev->dev_private; 272 drm_i915_private_t *dev_priv = dev->dev_private;
273 struct drm_mode_config *config = &dev->mode_config;
274 struct drm_plane *plane;
273 275
274 ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); 276 ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
275 if (ret) 277 if (ret)
276 DRM_DEBUG("failed to restore crtc mode\n"); 278 DRM_DEBUG("failed to restore crtc mode\n");
279
280 /* Be sure to shut off any planes that may be active */
281 list_for_each_entry(plane, &config->plane_list, head)
282 plane->funcs->disable_plane(plane);
277} 283}
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
new file mode 100644
index 000000000000..c77717db635b
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -0,0 +1,450 @@
1/*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Jesse Barnes <jbarnes@virtuousgeek.org>
25 *
26 * New plane/sprite handling.
27 *
28 * The older chips had a separate interface for programming plane related
29 * registers; newer ones are much simpler and we can use the new DRM plane
30 * support.
31 */
32#include "drmP.h"
33#include "drm_crtc.h"
34#include "drm_fourcc.h"
35#include "intel_drv.h"
36#include "i915_drm.h"
37#include "i915_drv.h"
38
39static void
40ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
41 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
42 unsigned int crtc_w, unsigned int crtc_h,
43 uint32_t x, uint32_t y,
44 uint32_t src_w, uint32_t src_h)
45{
46 struct drm_device *dev = plane->dev;
47 struct drm_i915_private *dev_priv = dev->dev_private;
48 struct intel_plane *intel_plane = to_intel_plane(plane);
49 int pipe = intel_plane->pipe;
50 u32 sprctl, sprscale = 0;
51 int pixel_size;
52
53 sprctl = I915_READ(SPRCTL(pipe));
54
55 /* Mask out pixel format bits in case we change it */
56 sprctl &= ~SPRITE_PIXFORMAT_MASK;
57 sprctl &= ~SPRITE_RGB_ORDER_RGBX;
58 sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
59
60 switch (fb->pixel_format) {
61 case DRM_FORMAT_XBGR8888:
62 sprctl |= SPRITE_FORMAT_RGBX888;
63 pixel_size = 4;
64 break;
65 case DRM_FORMAT_XRGB8888:
66 sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
67 pixel_size = 4;
68 break;
69 case DRM_FORMAT_YUYV:
70 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
71 pixel_size = 2;
72 break;
73 case DRM_FORMAT_YVYU:
74 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
75 pixel_size = 2;
76 break;
77 case DRM_FORMAT_UYVY:
78 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
79 pixel_size = 2;
80 break;
81 case DRM_FORMAT_VYUY:
82 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
83 pixel_size = 2;
84 break;
85 default:
86 DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
87 sprctl |= DVS_FORMAT_RGBX888;
88 pixel_size = 4;
89 break;
90 }
91
92 if (obj->tiling_mode != I915_TILING_NONE)
93 sprctl |= SPRITE_TILED;
94
95 /* must disable */
96 sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
97 sprctl |= SPRITE_ENABLE;
98
99 /* Sizes are 0 based */
100 src_w--;
101 src_h--;
102 crtc_w--;
103 crtc_h--;
104
105 intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
106
107 /*
108 * IVB workaround: must disable low power watermarks for at least
109 * one frame before enabling scaling. LP watermarks can be re-enabled
110 * when scaling is disabled.
111 */
112 if (crtc_w != src_w || crtc_h != src_h) {
113 dev_priv->sprite_scaling_enabled = true;
114 sandybridge_update_wm(dev);
115 intel_wait_for_vblank(dev, pipe);
116 sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
117 } else {
118 dev_priv->sprite_scaling_enabled = false;
119 /* potentially re-enable LP watermarks */
120 sandybridge_update_wm(dev);
121 }
122
123 I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
124 I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
125 if (obj->tiling_mode != I915_TILING_NONE) {
126 I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
127 } else {
128 unsigned long offset;
129
130 offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
131 I915_WRITE(SPRLINOFF(pipe), offset);
132 }
133 I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
134 I915_WRITE(SPRSCALE(pipe), sprscale);
135 I915_WRITE(SPRCTL(pipe), sprctl);
136 I915_WRITE(SPRSURF(pipe), obj->gtt_offset);
137 POSTING_READ(SPRSURF(pipe));
138}
139
140static void
141ivb_disable_plane(struct drm_plane *plane)
142{
143 struct drm_device *dev = plane->dev;
144 struct drm_i915_private *dev_priv = dev->dev_private;
145 struct intel_plane *intel_plane = to_intel_plane(plane);
146 int pipe = intel_plane->pipe;
147
148 I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
149 /* Can't leave the scaler enabled... */
150 I915_WRITE(SPRSCALE(pipe), 0);
151 /* Activate double buffered register update */
152 I915_WRITE(SPRSURF(pipe), 0);
153 POSTING_READ(SPRSURF(pipe));
154}
155
156static void
157snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
158 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
159 unsigned int crtc_w, unsigned int crtc_h,
160 uint32_t x, uint32_t y,
161 uint32_t src_w, uint32_t src_h)
162{
163 struct drm_device *dev = plane->dev;
164 struct drm_i915_private *dev_priv = dev->dev_private;
165 struct intel_plane *intel_plane = to_intel_plane(plane);
166 int pipe = intel_plane->pipe, pixel_size;
167 u32 dvscntr, dvsscale = 0;
168
169 dvscntr = I915_READ(DVSCNTR(pipe));
170
171 /* Mask out pixel format bits in case we change it */
172 dvscntr &= ~DVS_PIXFORMAT_MASK;
173 dvscntr &= ~DVS_RGB_ORDER_RGBX;
174 dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
175
176 switch (fb->pixel_format) {
177 case DRM_FORMAT_XBGR8888:
178 dvscntr |= DVS_FORMAT_RGBX888;
179 pixel_size = 4;
180 break;
181 case DRM_FORMAT_XRGB8888:
182 dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX;
183 pixel_size = 4;
184 break;
185 case DRM_FORMAT_YUYV:
186 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
187 pixel_size = 2;
188 break;
189 case DRM_FORMAT_YVYU:
190 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
191 pixel_size = 2;
192 break;
193 case DRM_FORMAT_UYVY:
194 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
195 pixel_size = 2;
196 break;
197 case DRM_FORMAT_VYUY:
198 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
199 pixel_size = 2;
200 break;
201 default:
202 DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
203 dvscntr |= DVS_FORMAT_RGBX888;
204 pixel_size = 4;
205 break;
206 }
207
208 if (obj->tiling_mode != I915_TILING_NONE)
209 dvscntr |= DVS_TILED;
210
211 /* must disable */
212 dvscntr |= DVS_TRICKLE_FEED_DISABLE;
213 dvscntr |= DVS_ENABLE;
214
215 /* Sizes are 0 based */
216 src_w--;
217 src_h--;
218 crtc_w--;
219 crtc_h--;
220
221 intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
222
223 if (crtc_w != src_w || crtc_h != src_h)
224 dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
225
226 I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
227 I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
228 if (obj->tiling_mode != I915_TILING_NONE) {
229 I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
230 } else {
231 unsigned long offset;
232
233 offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
234 I915_WRITE(DVSLINOFF(pipe), offset);
235 }
236 I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
237 I915_WRITE(DVSSCALE(pipe), dvsscale);
238 I915_WRITE(DVSCNTR(pipe), dvscntr);
239 I915_WRITE(DVSSURF(pipe), obj->gtt_offset);
240 POSTING_READ(DVSSURF(pipe));
241}
242
243static void
244snb_disable_plane(struct drm_plane *plane)
245{
246 struct drm_device *dev = plane->dev;
247 struct drm_i915_private *dev_priv = dev->dev_private;
248 struct intel_plane *intel_plane = to_intel_plane(plane);
249 int pipe = intel_plane->pipe;
250
251 I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
252 /* Disable the scaler */
253 I915_WRITE(DVSSCALE(pipe), 0);
254 /* Flush double buffered register updates */
255 I915_WRITE(DVSSURF(pipe), 0);
256 POSTING_READ(DVSSURF(pipe));
257}
258
259static int
260intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
261 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
262 unsigned int crtc_w, unsigned int crtc_h,
263 uint32_t src_x, uint32_t src_y,
264 uint32_t src_w, uint32_t src_h)
265{
266 struct drm_device *dev = plane->dev;
267 struct drm_i915_private *dev_priv = dev->dev_private;
268 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
269 struct intel_plane *intel_plane = to_intel_plane(plane);
270 struct intel_framebuffer *intel_fb;
271 struct drm_i915_gem_object *obj, *old_obj;
272 int pipe = intel_plane->pipe;
273 int ret = 0;
274 int x = src_x >> 16, y = src_y >> 16;
275 int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
276 bool disable_primary = false;
277
278 intel_fb = to_intel_framebuffer(fb);
279 obj = intel_fb->obj;
280
281 old_obj = intel_plane->obj;
282
283 /* Pipe must be running... */
284 if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
285 return -EINVAL;
286
287 if (crtc_x >= primary_w || crtc_y >= primary_h)
288 return -EINVAL;
289
290 /* Don't modify another pipe's plane */
291 if (intel_plane->pipe != intel_crtc->pipe)
292 return -EINVAL;
293
294 /*
295 * Clamp the width & height into the visible area. Note we don't
296 * try to scale the source if part of the visible region is offscreen.
297 * The caller must handle that by adjusting source offset and size.
298 */
299 if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) {
300 crtc_w += crtc_x;
301 crtc_x = 0;
302 }
303 if ((crtc_x + crtc_w) <= 0) /* Nothing to display */
304 goto out;
305 if ((crtc_x + crtc_w) > primary_w)
306 crtc_w = primary_w - crtc_x;
307
308 if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) {
309 crtc_h += crtc_y;
310 crtc_y = 0;
311 }
312 if ((crtc_y + crtc_h) <= 0) /* Nothing to display */
313 goto out;
314 if (crtc_y + crtc_h > primary_h)
315 crtc_h = primary_h - crtc_y;
316
317 if (!crtc_w || !crtc_h) /* Again, nothing to display */
318 goto out;
319
320 /*
321 * We can take a larger source and scale it down, but
322 * only so much... 16x is the max on SNB.
323 */
324 if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale)
325 return -EINVAL;
326
327 /*
328 * If the sprite is completely covering the primary plane,
329 * we can disable the primary and save power.
330 */
331 if ((crtc_x == 0) && (crtc_y == 0) &&
332 (crtc_w == primary_w) && (crtc_h == primary_h))
333 disable_primary = true;
334
335 mutex_lock(&dev->struct_mutex);
336
337 ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
338 if (ret) {
339 DRM_ERROR("failed to pin object\n");
340 goto out_unlock;
341 }
342
343 intel_plane->obj = obj;
344
345 intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
346 crtc_w, crtc_h, x, y, src_w, src_h);
347
348 /* Unpin old obj after new one is active to avoid ugliness */
349 if (old_obj) {
350 /*
351 * It's fairly common to simply update the position of
352 * an existing object. In that case, we don't need to
353 * wait for vblank to avoid ugliness, we only need to
354 * do the pin & ref bookkeeping.
355 */
356 if (old_obj != obj) {
357 mutex_unlock(&dev->struct_mutex);
358 intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
359 mutex_lock(&dev->struct_mutex);
360 }
361 i915_gem_object_unpin(old_obj);
362 }
363
364out_unlock:
365 mutex_unlock(&dev->struct_mutex);
366out:
367 return ret;
368}
369
370static int
371intel_disable_plane(struct drm_plane *plane)
372{
373 struct drm_device *dev = plane->dev;
374 struct intel_plane *intel_plane = to_intel_plane(plane);
375 int ret = 0;
376
377 intel_plane->disable_plane(plane);
378
379 if (!intel_plane->obj)
380 goto out;
381
382 mutex_lock(&dev->struct_mutex);
383 i915_gem_object_unpin(intel_plane->obj);
384 intel_plane->obj = NULL;
385 mutex_unlock(&dev->struct_mutex);
386out:
387
388 return ret;
389}
390
391static void intel_destroy_plane(struct drm_plane *plane)
392{
393 struct intel_plane *intel_plane = to_intel_plane(plane);
394 intel_disable_plane(plane);
395 drm_plane_cleanup(plane);
396 kfree(intel_plane);
397}
398
399static const struct drm_plane_funcs intel_plane_funcs = {
400 .update_plane = intel_update_plane,
401 .disable_plane = intel_disable_plane,
402 .destroy = intel_destroy_plane,
403};
404
405static uint32_t snb_plane_formats[] = {
406 DRM_FORMAT_XBGR8888,
407 DRM_FORMAT_XRGB8888,
408 DRM_FORMAT_YUYV,
409 DRM_FORMAT_YVYU,
410 DRM_FORMAT_UYVY,
411 DRM_FORMAT_VYUY,
412};
413
414int
415intel_plane_init(struct drm_device *dev, enum pipe pipe)
416{
417 struct intel_plane *intel_plane;
418 unsigned long possible_crtcs;
419 int ret;
420
421 if (!(IS_GEN6(dev) || IS_GEN7(dev))) {
422 DRM_ERROR("new plane code only for SNB+\n");
423 return -ENODEV;
424 }
425
426 intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL);
427 if (!intel_plane)
428 return -ENOMEM;
429
430 if (IS_GEN6(dev)) {
431 intel_plane->max_downscale = 16;
432 intel_plane->update_plane = snb_update_plane;
433 intel_plane->disable_plane = snb_disable_plane;
434 } else if (IS_GEN7(dev)) {
435 intel_plane->max_downscale = 2;
436 intel_plane->update_plane = ivb_update_plane;
437 intel_plane->disable_plane = ivb_disable_plane;
438 }
439
440 intel_plane->pipe = pipe;
441 possible_crtcs = (1 << pipe);
442 ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
443 &intel_plane_funcs, snb_plane_formats,
444 ARRAY_SIZE(snb_plane_formats));
445 if (ret)
446 kfree(intel_plane);
447
448 return ret;
449}
450