diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 133 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 174 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fb.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 450 |
7 files changed, 788 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0ae6a7c5020..808b255d7fc 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 621840c05f0..602bc80baab 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 44eabb088b4..d791043c8ec 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 ff99fa267bf..30397b74a4a 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 | ||
918 | static void assert_pipe(struct drm_i915_private *dev_priv, | 918 | void 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 | ||
935 | static void assert_plane_enabled(struct drm_i915_private *dev_priv, | 933 | static 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 | ||
4512 | static void sandybridge_update_wm(struct drm_device *dev) | 4510 | void 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 | ||
4621 | static bool | ||
4622 | sandybridge_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 | |||
4653 | static bool | ||
4654 | sandybridge_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 | |||
4688 | static 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 | ||
4804 | void 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 | |||
4662 | static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) | 4814 | static 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) | |||
8827 | void intel_modeset_init(struct drm_device *dev) | 8981 | void 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 82a459bfccb..a6e2f0d865b 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 | ||
180 | struct 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, | |||
290 | extern bool intel_dpd_is_edp(struct drm_device *dev); | 307 | extern bool intel_dpd_is_edp(struct drm_device *dev); |
291 | extern void intel_edp_link_config(struct intel_encoder *, int *, int *); | 308 | extern void intel_edp_link_config(struct intel_encoder *, int *, int *); |
292 | extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); | 309 | extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); |
310 | extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); | ||
293 | 311 | ||
294 | /* intel_panel.c */ | 312 | /* intel_panel.c */ |
295 | extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, | 313 | extern 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, | |||
380 | extern void intel_fb_output_poll_changed(struct drm_device *dev); | 398 | extern void intel_fb_output_poll_changed(struct drm_device *dev); |
381 | extern void intel_fb_restore_mode(struct drm_device *dev); | 399 | extern void intel_fb_restore_mode(struct drm_device *dev); |
382 | 400 | ||
401 | extern 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 | |||
383 | extern void intel_init_clock_gating(struct drm_device *dev); | 406 | extern void intel_init_clock_gating(struct drm_device *dev); |
384 | extern void intel_write_eld(struct drm_encoder *encoder, | 407 | extern void intel_write_eld(struct drm_encoder *encoder, |
385 | struct drm_display_mode *mode); | 408 | struct drm_display_mode *mode); |
386 | extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); | 409 | extern 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 */ | ||
412 | extern void sandybridge_update_wm(struct drm_device *dev); | ||
413 | extern 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 f02fc71a57a..571375a3eef 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 00000000000..c77717db635 --- /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 | |||
39 | static void | ||
40 | ivb_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 | |||
140 | static void | ||
141 | ivb_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 | |||
156 | static void | ||
157 | snb_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 | |||
243 | static void | ||
244 | snb_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 | |||
259 | static int | ||
260 | intel_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 | |||
364 | out_unlock: | ||
365 | mutex_unlock(&dev->struct_mutex); | ||
366 | out: | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | static int | ||
371 | intel_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); | ||
386 | out: | ||
387 | |||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | static 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 | |||
399 | static 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 | |||
405 | static 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 | |||
414 | int | ||
415 | intel_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 | |||