aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2013-06-26 17:39:25 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-07-01 13:37:53 -0400
commitf1f644dc66cbaf5a4c7dcde683361536b41885b9 (patch)
treeca7844bb05bb6dcbc23fd5c24d2f54644656a967 /drivers/gpu/drm/i915/intel_display.c
parent2385bdf0787aef45ee1847b8508a417433da7e14 (diff)
drm/i915: get mode clock when reading the pipe config v9
We need this for comparing modes between configuration changes. The tricky part is to allow us to reuse the new get_clock stuff to recover the lvds clock on gen2/3 when neither the vbt has an lvds mode nor the panel a (useful) EDID. v2: try harder to calulate non-simple pixel clocks (Daniel) call get_clock after getting the encoder config, needed for pixel multiply (Jesse) v3: drop get_clock now that the pixel_multiply has been moved into get_pipe_config v4: re-add get_clock; we need to get the pixel multiplier in the encoder, so need to calculate the clock value after the encoder's get_config is called v5: drop hsw clock_get, still needs to be written v6: add fuzzy clock check (Daniel) v7: wrap fuzzy clock check under !IS_HASWELL use port_clock field rather than a new CPU eDP clock field in crtc_config v8: remove stale pixel_multiplier sets (Daniel) multiply by pixel_multiplier in 9xx clock get too (Daniel) v9: make sure we set pixel_multiplier before calling clock_get from mode_get for LVDS (Daniel) Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> [danvet: Add some explanation to the commit message about why we have to jump through a few hoops. Also remove the rebase-fail hunk from intel_sdvo.c] [danvet: Squash in the fixup from Jesse to also call ->get_clock in the modeset state checker.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c126
1 files changed, 115 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 65e8f5e512d2..9c05e57fb7ae 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -45,6 +45,11 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
45static void intel_increase_pllclock(struct drm_crtc *crtc); 45static void intel_increase_pllclock(struct drm_crtc *crtc);
46static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); 46static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
47 47
48static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
49 struct intel_crtc_config *pipe_config);
50static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
51 struct intel_crtc_config *pipe_config);
52
48typedef struct { 53typedef struct {
49 int min, max; 54 int min, max;
50} intel_range_t; 55} intel_range_t;
@@ -6853,11 +6858,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
6853} 6858}
6854 6859
6855/* Returns the clock of the currently programmed mode of the given pipe. */ 6860/* Returns the clock of the currently programmed mode of the given pipe. */
6856static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) 6861static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
6862 struct intel_crtc_config *pipe_config)
6857{ 6863{
6864 struct drm_device *dev = crtc->base.dev;
6858 struct drm_i915_private *dev_priv = dev->dev_private; 6865 struct drm_i915_private *dev_priv = dev->dev_private;
6859 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 6866 int pipe = pipe_config->cpu_transcoder;
6860 int pipe = intel_crtc->pipe;
6861 u32 dpll = I915_READ(DPLL(pipe)); 6867 u32 dpll = I915_READ(DPLL(pipe));
6862 u32 fp; 6868 u32 fp;
6863 intel_clock_t clock; 6869 intel_clock_t clock;
@@ -6896,7 +6902,8 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
6896 default: 6902 default:
6897 DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed " 6903 DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
6898 "mode\n", (int)(dpll & DPLL_MODE_MASK)); 6904 "mode\n", (int)(dpll & DPLL_MODE_MASK));
6899 return 0; 6905 pipe_config->adjusted_mode.clock = 0;
6906 return;
6900 } 6907 }
6901 6908
6902 if (IS_PINEVIEW(dev)) 6909 if (IS_PINEVIEW(dev))
@@ -6933,12 +6940,55 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
6933 } 6940 }
6934 } 6941 }
6935 6942
6936 /* XXX: It would be nice to validate the clocks, but we can't reuse 6943 pipe_config->adjusted_mode.clock = clock.dot *
6937 * i830PllIsValid() because it relies on the xf86_config connector 6944 pipe_config->pixel_multiplier;
6938 * configuration being accurate, which it isn't necessarily. 6945}
6946
6947static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
6948 struct intel_crtc_config *pipe_config)
6949{
6950 struct drm_device *dev = crtc->base.dev;
6951 struct drm_i915_private *dev_priv = dev->dev_private;
6952 enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
6953 int link_freq, repeat;
6954 u64 clock;
6955 u32 link_m, link_n;
6956
6957 repeat = pipe_config->pixel_multiplier;
6958
6959 /*
6960 * The calculation for the data clock is:
6961 * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp
6962 * But we want to avoid losing precison if possible, so:
6963 * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp))
6964 *
6965 * and the link clock is simpler:
6966 * link_clock = (m * link_clock * repeat) / n
6967 */
6968
6969 /*
6970 * We need to get the FDI or DP link clock here to derive
6971 * the M/N dividers.
6972 *
6973 * For FDI, we read it from the BIOS or use a fixed 2.7GHz.
6974 * For DP, it's either 1.62GHz or 2.7GHz.
6975 * We do our calculations in 10*MHz since we don't need much precison.
6939 */ 6976 */
6977 if (pipe_config->has_pch_encoder)
6978 link_freq = intel_fdi_link_freq(dev) * 10000;
6979 else
6980 link_freq = pipe_config->port_clock;
6981
6982 link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
6983 link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder));
6984
6985 if (!link_m || !link_n)
6986 return;
6940 6987
6941 return clock.dot; 6988 clock = ((u64)link_m * (u64)link_freq * (u64)repeat);
6989 do_div(clock, link_n);
6990
6991 pipe_config->adjusted_mode.clock = clock;
6942} 6992}
6943 6993
6944/** Returns the currently programmed mode of the given pipe. */ 6994/** Returns the currently programmed mode of the given pipe. */
@@ -6949,6 +6999,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
6949 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 6999 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
6950 enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; 7000 enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
6951 struct drm_display_mode *mode; 7001 struct drm_display_mode *mode;
7002 struct intel_crtc_config pipe_config;
6952 int htot = I915_READ(HTOTAL(cpu_transcoder)); 7003 int htot = I915_READ(HTOTAL(cpu_transcoder));
6953 int hsync = I915_READ(HSYNC(cpu_transcoder)); 7004 int hsync = I915_READ(HSYNC(cpu_transcoder));
6954 int vtot = I915_READ(VTOTAL(cpu_transcoder)); 7005 int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -6958,7 +7009,18 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
6958 if (!mode) 7009 if (!mode)
6959 return NULL; 7010 return NULL;
6960 7011
6961 mode->clock = intel_crtc_clock_get(dev, crtc); 7012 /*
7013 * Construct a pipe_config sufficient for getting the clock info
7014 * back out of crtc_clock_get.
7015 *
7016 * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need
7017 * to use a real value here instead.
7018 */
7019 pipe_config.cpu_transcoder = intel_crtc->pipe;
7020 pipe_config.pixel_multiplier = 1;
7021 i9xx_crtc_clock_get(intel_crtc, &pipe_config);
7022
7023 mode->clock = pipe_config.adjusted_mode.clock;
6962 mode->hdisplay = (htot & 0xffff) + 1; 7024 mode->hdisplay = (htot & 0xffff) + 1;
6963 mode->htotal = ((htot & 0xffff0000) >> 16) + 1; 7025 mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
6964 mode->hsync_start = (hsync & 0xffff) + 1; 7026 mode->hsync_start = (hsync & 0xffff) + 1;
@@ -8019,6 +8081,28 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
8019 8081
8020} 8082}
8021 8083
8084static bool intel_fuzzy_clock_check(struct intel_crtc_config *cur,
8085 struct intel_crtc_config *new)
8086{
8087 int clock1, clock2, diff;
8088
8089 clock1 = cur->adjusted_mode.clock;
8090 clock2 = new->adjusted_mode.clock;
8091
8092 if (clock1 == clock2)
8093 return true;
8094
8095 if (!clock1 || !clock2)
8096 return false;
8097
8098 diff = abs(clock1 - clock2);
8099
8100 if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105)
8101 return true;
8102
8103 return false;
8104}
8105
8022#define for_each_intel_crtc_masked(dev, mask, intel_crtc) \ 8106#define for_each_intel_crtc_masked(dev, mask, intel_crtc) \
8023 list_for_each_entry((intel_crtc), \ 8107 list_for_each_entry((intel_crtc), \
8024 &(dev)->mode_config.crtc_list, \ 8108 &(dev)->mode_config.crtc_list, \
@@ -8124,6 +8208,15 @@ intel_pipe_config_compare(struct drm_device *dev,
8124#undef PIPE_CONF_CHECK_FLAGS 8208#undef PIPE_CONF_CHECK_FLAGS
8125#undef PIPE_CONF_QUIRK 8209#undef PIPE_CONF_QUIRK
8126 8210
8211 if (!IS_HASWELL(dev)) {
8212 if (!intel_fuzzy_clock_check(current_config, pipe_config)) {
8213 DRM_ERROR("mismatch in clock (expected %d, found %d\n",
8214 current_config->adjusted_mode.clock,
8215 pipe_config->adjusted_mode.clock);
8216 return false;
8217 }
8218 }
8219
8127 return true; 8220 return true;
8128} 8221}
8129 8222
@@ -8249,8 +8342,12 @@ check_crtc_state(struct drm_device *dev)
8249 base.head) { 8342 base.head) {
8250 if (encoder->base.crtc != &crtc->base) 8343 if (encoder->base.crtc != &crtc->base)
8251 continue; 8344 continue;
8252 if (encoder->get_config) 8345 if (encoder->get_config &&
8346 dev_priv->display.get_clock) {
8253 encoder->get_config(encoder, &pipe_config); 8347 encoder->get_config(encoder, &pipe_config);
8348 dev_priv->display.get_clock(crtc,
8349 &pipe_config);
8350 }
8254 } 8351 }
8255 8352
8256 WARN(crtc->active != active, 8353 WARN(crtc->active != active,
@@ -9253,6 +9350,7 @@ static void intel_init_display(struct drm_device *dev)
9253 dev_priv->display.update_plane = ironlake_update_plane; 9350 dev_priv->display.update_plane = ironlake_update_plane;
9254 } else if (HAS_PCH_SPLIT(dev)) { 9351 } else if (HAS_PCH_SPLIT(dev)) {
9255 dev_priv->display.get_pipe_config = ironlake_get_pipe_config; 9352 dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
9353 dev_priv->display.get_clock = ironlake_crtc_clock_get;
9256 dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; 9354 dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
9257 dev_priv->display.crtc_enable = ironlake_crtc_enable; 9355 dev_priv->display.crtc_enable = ironlake_crtc_enable;
9258 dev_priv->display.crtc_disable = ironlake_crtc_disable; 9356 dev_priv->display.crtc_disable = ironlake_crtc_disable;
@@ -9260,6 +9358,7 @@ static void intel_init_display(struct drm_device *dev)
9260 dev_priv->display.update_plane = ironlake_update_plane; 9358 dev_priv->display.update_plane = ironlake_update_plane;
9261 } else if (IS_VALLEYVIEW(dev)) { 9359 } else if (IS_VALLEYVIEW(dev)) {
9262 dev_priv->display.get_pipe_config = i9xx_get_pipe_config; 9360 dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
9361 dev_priv->display.get_clock = i9xx_crtc_clock_get;
9263 dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; 9362 dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
9264 dev_priv->display.crtc_enable = valleyview_crtc_enable; 9363 dev_priv->display.crtc_enable = valleyview_crtc_enable;
9265 dev_priv->display.crtc_disable = i9xx_crtc_disable; 9364 dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9267,6 +9366,7 @@ static void intel_init_display(struct drm_device *dev)
9267 dev_priv->display.update_plane = i9xx_update_plane; 9366 dev_priv->display.update_plane = i9xx_update_plane;
9268 } else { 9367 } else {
9269 dev_priv->display.get_pipe_config = i9xx_get_pipe_config; 9368 dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
9369 dev_priv->display.get_clock = i9xx_crtc_clock_get;
9270 dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; 9370 dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
9271 dev_priv->display.crtc_enable = i9xx_crtc_enable; 9371 dev_priv->display.crtc_enable = i9xx_crtc_enable;
9272 dev_priv->display.crtc_disable = i9xx_crtc_disable; 9372 dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9813,8 +9913,12 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
9813 if (encoder->get_hw_state(encoder, &pipe)) { 9913 if (encoder->get_hw_state(encoder, &pipe)) {
9814 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); 9914 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
9815 encoder->base.crtc = &crtc->base; 9915 encoder->base.crtc = &crtc->base;
9816 if (encoder->get_config) 9916 if (encoder->get_config &&
9917 dev_priv->display.get_clock) {
9817 encoder->get_config(encoder, &crtc->config); 9918 encoder->get_config(encoder, &crtc->config);
9919 dev_priv->display.get_clock(crtc,
9920 &crtc->config);
9921 }
9818 } else { 9922 } else {
9819 encoder->base.crtc = NULL; 9923 encoder->base.crtc = NULL;
9820 } 9924 }