diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2013-06-26 17:39:25 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-07-01 13:37:53 -0400 |
commit | f1f644dc66cbaf5a4c7dcde683361536b41885b9 (patch) | |
tree | ca7844bb05bb6dcbc23fd5c24d2f54644656a967 /drivers/gpu/drm/i915/intel_display.c | |
parent | 2385bdf0787aef45ee1847b8508a417433da7e14 (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.c | 126 |
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); | |||
45 | static void intel_increase_pllclock(struct drm_crtc *crtc); | 45 | static void intel_increase_pllclock(struct drm_crtc *crtc); |
46 | static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); | 46 | static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); |
47 | 47 | ||
48 | static void i9xx_crtc_clock_get(struct intel_crtc *crtc, | ||
49 | struct intel_crtc_config *pipe_config); | ||
50 | static void ironlake_crtc_clock_get(struct intel_crtc *crtc, | ||
51 | struct intel_crtc_config *pipe_config); | ||
52 | |||
48 | typedef struct { | 53 | typedef 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. */ |
6856 | static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) | 6861 | static 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 | |||
6947 | static 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 | ||
8084 | static 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 | } |