diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 56 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 2 |
4 files changed, 62 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ef44b2a6952..f40a28589eea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -4040,13 +4040,16 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, | |||
4040 | } | 4040 | } |
4041 | } | 4041 | } |
4042 | 4042 | ||
4043 | static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, | 4043 | #define RETRY 1 |
4044 | struct intel_crtc_config *pipe_config) | 4044 | static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, |
4045 | struct intel_crtc_config *pipe_config) | ||
4045 | { | 4046 | { |
4046 | struct drm_device *dev = intel_crtc->base.dev; | 4047 | struct drm_device *dev = intel_crtc->base.dev; |
4047 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | 4048 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
4048 | int target_clock, lane, link_bw; | 4049 | int target_clock, lane, link_bw; |
4050 | bool setup_ok, needs_recompute = false; | ||
4049 | 4051 | ||
4052 | retry: | ||
4050 | /* FDI is a binary signal running at ~2.7GHz, encoding | 4053 | /* FDI is a binary signal running at ~2.7GHz, encoding |
4051 | * each output octet as 10 bits. The actual frequency | 4054 | * each output octet as 10 bits. The actual frequency |
4052 | * is stored as a divider into a 100MHz clock, and the | 4055 | * is stored as a divider into a 100MHz clock, and the |
@@ -4071,12 +4074,26 @@ static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, | |||
4071 | intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, | 4074 | intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, |
4072 | link_bw, &pipe_config->fdi_m_n); | 4075 | link_bw, &pipe_config->fdi_m_n); |
4073 | 4076 | ||
4074 | return ironlake_check_fdi_lanes(intel_crtc->base.dev, | 4077 | setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev, |
4075 | intel_crtc->pipe, pipe_config); | 4078 | intel_crtc->pipe, pipe_config); |
4079 | if (!setup_ok && pipe_config->pipe_bpp > 6*3) { | ||
4080 | pipe_config->pipe_bpp -= 2*3; | ||
4081 | DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n", | ||
4082 | pipe_config->pipe_bpp); | ||
4083 | needs_recompute = true; | ||
4084 | pipe_config->bw_constrained = true; | ||
4085 | |||
4086 | goto retry; | ||
4087 | } | ||
4088 | |||
4089 | if (needs_recompute) | ||
4090 | return RETRY; | ||
4091 | |||
4092 | return setup_ok ? 0 : -EINVAL; | ||
4076 | } | 4093 | } |
4077 | 4094 | ||
4078 | static bool intel_crtc_compute_config(struct drm_crtc *crtc, | 4095 | static int intel_crtc_compute_config(struct drm_crtc *crtc, |
4079 | struct intel_crtc_config *pipe_config) | 4096 | struct intel_crtc_config *pipe_config) |
4080 | { | 4097 | { |
4081 | struct drm_device *dev = crtc->dev; | 4098 | struct drm_device *dev = crtc->dev; |
4082 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | 4099 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
@@ -4085,7 +4102,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, | |||
4085 | /* FDI link clock is fixed at 2.7G */ | 4102 | /* FDI link clock is fixed at 2.7G */ |
4086 | if (pipe_config->requested_mode.clock * 3 | 4103 | if (pipe_config->requested_mode.clock * 3 |
4087 | > IRONLAKE_FDI_FREQ * 4) | 4104 | > IRONLAKE_FDI_FREQ * 4) |
4088 | return false; | 4105 | return -EINVAL; |
4089 | } | 4106 | } |
4090 | 4107 | ||
4091 | /* All interlaced capable intel hw wants timings in frames. Note though | 4108 | /* All interlaced capable intel hw wants timings in frames. Note though |
@@ -4099,7 +4116,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, | |||
4099 | */ | 4116 | */ |
4100 | if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && | 4117 | if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && |
4101 | adjusted_mode->hsync_start == adjusted_mode->hdisplay) | 4118 | adjusted_mode->hsync_start == adjusted_mode->hdisplay) |
4102 | return false; | 4119 | return -EINVAL; |
4103 | 4120 | ||
4104 | if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { | 4121 | if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { |
4105 | pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ | 4122 | pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ |
@@ -4112,7 +4129,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, | |||
4112 | if (pipe_config->has_pch_encoder) | 4129 | if (pipe_config->has_pch_encoder) |
4113 | return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); | 4130 | return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); |
4114 | 4131 | ||
4115 | return true; | 4132 | return 0; |
4116 | } | 4133 | } |
4117 | 4134 | ||
4118 | static int valleyview_get_display_clock_speed(struct drm_device *dev) | 4135 | static int valleyview_get_display_clock_speed(struct drm_device *dev) |
@@ -7692,7 +7709,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, | |||
7692 | struct drm_encoder_helper_funcs *encoder_funcs; | 7709 | struct drm_encoder_helper_funcs *encoder_funcs; |
7693 | struct intel_encoder *encoder; | 7710 | struct intel_encoder *encoder; |
7694 | struct intel_crtc_config *pipe_config; | 7711 | struct intel_crtc_config *pipe_config; |
7695 | int plane_bpp; | 7712 | int plane_bpp, ret = -EINVAL; |
7713 | bool retry = true; | ||
7696 | 7714 | ||
7697 | pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); | 7715 | pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); |
7698 | if (!pipe_config) | 7716 | if (!pipe_config) |
@@ -7705,6 +7723,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, | |||
7705 | if (plane_bpp < 0) | 7723 | if (plane_bpp < 0) |
7706 | goto fail; | 7724 | goto fail; |
7707 | 7725 | ||
7726 | encoder_retry: | ||
7708 | /* Pass our mode to the connectors and the CRTC to give them a chance to | 7727 | /* Pass our mode to the connectors and the CRTC to give them a chance to |
7709 | * adjust it according to limitations or connector properties, and also | 7728 | * adjust it according to limitations or connector properties, and also |
7710 | * a chance to reject the mode entirely. | 7729 | * a chance to reject the mode entirely. |
@@ -7733,10 +7752,23 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, | |||
7733 | } | 7752 | } |
7734 | } | 7753 | } |
7735 | 7754 | ||
7736 | if (!(intel_crtc_compute_config(crtc, pipe_config))) { | 7755 | ret = intel_crtc_compute_config(crtc, pipe_config); |
7756 | if (ret < 0) { | ||
7737 | DRM_DEBUG_KMS("CRTC fixup failed\n"); | 7757 | DRM_DEBUG_KMS("CRTC fixup failed\n"); |
7738 | goto fail; | 7758 | goto fail; |
7739 | } | 7759 | } |
7760 | |||
7761 | if (ret == RETRY) { | ||
7762 | if (WARN(!retry, "loop in pipe configuration computation\n")) { | ||
7763 | ret = -EINVAL; | ||
7764 | goto fail; | ||
7765 | } | ||
7766 | |||
7767 | DRM_DEBUG_KMS("CRTC bw constrained, retrying\n"); | ||
7768 | retry = false; | ||
7769 | goto encoder_retry; | ||
7770 | } | ||
7771 | |||
7740 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); | 7772 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
7741 | 7773 | ||
7742 | pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; | 7774 | pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; |
@@ -7746,7 +7778,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, | |||
7746 | return pipe_config; | 7778 | return pipe_config; |
7747 | fail: | 7779 | fail: |
7748 | kfree(pipe_config); | 7780 | kfree(pipe_config); |
7749 | return ERR_PTR(-EINVAL); | 7781 | return ERR_PTR(ret); |
7750 | } | 7782 | } |
7751 | 7783 | ||
7752 | /* Computes which crtcs are affected and sets the relevant bits in the mask. For | 7784 | /* Computes which crtcs are affected and sets the relevant bits in the mask. For |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 48f309eaf7aa..766afcf39ee9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -223,6 +223,13 @@ struct intel_crtc_config { | |||
223 | /* Controls for the clock computation, to override various stages. */ | 223 | /* Controls for the clock computation, to override various stages. */ |
224 | bool clock_set; | 224 | bool clock_set; |
225 | 225 | ||
226 | /* | ||
227 | * crtc bandwidth limit, don't increase pipe bpp or clock if not really | ||
228 | * required. This is set in the 2nd loop of calling encoder's | ||
229 | * ->compute_config if the first pick doesn't work out. | ||
230 | */ | ||
231 | bool bw_constrained; | ||
232 | |||
226 | /* Settings for the intel dpll used on pretty much everything but | 233 | /* Settings for the intel dpll used on pretty much everything but |
227 | * haswell. */ | 234 | * haswell. */ |
228 | struct dpll dpll; | 235 | struct dpll dpll; |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 21302db7f76d..93de5ff77912 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
@@ -784,6 +784,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
784 | struct drm_device *dev = encoder->base.dev; | 784 | struct drm_device *dev = encoder->base.dev; |
785 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | 785 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
786 | int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2; | 786 | int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2; |
787 | int desired_bpp; | ||
787 | 788 | ||
788 | if (intel_hdmi->color_range_auto) { | 789 | if (intel_hdmi->color_range_auto) { |
789 | /* See CEA-861-E - 5.1 Default Encoding Parameters */ | 790 | /* See CEA-861-E - 5.1 Default Encoding Parameters */ |
@@ -808,16 +809,21 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
808 | */ | 809 | */ |
809 | if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000 | 810 | if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000 |
810 | && HAS_PCH_SPLIT(dev)) { | 811 | && HAS_PCH_SPLIT(dev)) { |
811 | DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); | 812 | DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); |
812 | pipe_config->pipe_bpp = 12*3; | 813 | desired_bpp = 12*3; |
813 | 814 | ||
814 | /* Need to adjust the port link by 1.5x for 12bpc. */ | 815 | /* Need to adjust the port link by 1.5x for 12bpc. */ |
815 | adjusted_mode->clock = clock_12bpc; | 816 | adjusted_mode->clock = clock_12bpc; |
816 | pipe_config->pixel_target_clock = | 817 | pipe_config->pixel_target_clock = |
817 | pipe_config->requested_mode.clock; | 818 | pipe_config->requested_mode.clock; |
818 | } else { | 819 | } else { |
819 | DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); | 820 | DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); |
820 | pipe_config->pipe_bpp = 8*3; | 821 | desired_bpp = 8*3; |
822 | } | ||
823 | |||
824 | if (!pipe_config->bw_constrained) { | ||
825 | DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); | ||
826 | pipe_config->pipe_bpp = desired_bpp; | ||
821 | } | 827 | } |
822 | 828 | ||
823 | if (adjusted_mode->clock > 225000) { | 829 | if (adjusted_mode->clock > 225000) { |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3e29499b2e9a..8d65baf043ea 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -248,7 +248,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
248 | else | 248 | else |
249 | lvds_bpp = 6*3; | 249 | lvds_bpp = 6*3; |
250 | 250 | ||
251 | if (lvds_bpp != pipe_config->pipe_bpp) { | 251 | if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) { |
252 | DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", | 252 | DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", |
253 | pipe_config->pipe_bpp, lvds_bpp); | 253 | pipe_config->pipe_bpp, lvds_bpp); |
254 | pipe_config->pipe_bpp = lvds_bpp; | 254 | pipe_config->pipe_bpp = lvds_bpp; |