aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
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/drm/i915/intel_display.c
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/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c174
1 files changed, 167 insertions, 7 deletions
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
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 */