diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 290017857c6dac1679573d2d989eeb10fd4ac40f..3e36af90f94305eb3999000bb4f2931cd9d8c116 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -619,7 +619,8 @@ struct drm_i915_display_funcs { struct drm_crtc *crtc, uint32_t sprite_width, uint32_t sprite_height, int pixel_size, bool enable, bool scaled); - void (*modeset_global_resources)(struct drm_atomic_state *state); + int (*modeset_calc_cdclk)(struct drm_atomic_state *state); + void (*modeset_commit_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 060d98b10f83f25deeb1d31eeea0b76360fb4e94..0aeced82201e44a831d8ca2f08e67574fa9a8783 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -54,6 +54,8 @@ int intel_atomic_check(struct drm_device *dev, int i; bool not_nuclear = false; + to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq; + /* * FIXME: At the moment, we only support "nuclear pageflip" on a * single CRTC. Cross-crtc updates will be added later. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 30ffca865e1d7f31ef9dc13860e42c83230c5210..64c6c38ec8af2296fdf57a0661276527a3ee5e4d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5204,8 +5204,13 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_power_get(dev_priv, domain); } - if (dev_priv->display.modeset_global_resources) - dev_priv->display.modeset_global_resources(state); + if (dev_priv->display.modeset_commit_cdclk) { + unsigned int cdclk = to_intel_atomic_state(state)->cdclk; + + if (cdclk != dev_priv->cdclk_freq && + !WARN_ON(!state->allow_modeset)) + dev_priv->display.modeset_commit_cdclk(state); + } for_each_intel_crtc(dev, crtc) { enum intel_display_power_domain domain; @@ -5859,11 +5864,7 @@ static int intel_mode_max_pixclk(struct drm_device *dev, int max_pixclk = 0; for_each_intel_crtc(dev, intel_crtc) { - if (state) - crtc_state = - intel_atomic_get_crtc_state(state, intel_crtc); - else - crtc_state = intel_crtc->config; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); @@ -5877,46 +5878,34 @@ static int intel_mode_max_pixclk(struct drm_device *dev, return max_pixclk; } -static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) +static int valleyview_modeset_calc_cdclk(struct drm_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int max_pixclk = intel_mode_max_pixclk(state->dev, state); - int cdclk, ret = 0; + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev, state); if (max_pixclk < 0) return max_pixclk; - if (IS_VALLEYVIEW(dev_priv)) - cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - else - cdclk = broxton_calc_cdclk(dev_priv, max_pixclk); - - if (cdclk == dev_priv->cdclk_freq) - return 0; - - /* add all active pipes to the state */ - for_each_crtc(state->dev, crtc) { - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); + to_intel_atomic_state(state)->cdclk = + valleyview_calc_cdclk(dev_priv, max_pixclk); - if (!crtc_state->active || needs_modeset(crtc_state)) - continue; + return 0; +} - crtc_state->mode_changed = true; +static int broxton_modeset_calc_cdclk(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev, state); - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - break; + if (max_pixclk < 0) + return max_pixclk; - ret = drm_atomic_add_affected_planes(state, crtc); - if (ret) - break; - } + to_intel_atomic_state(state)->cdclk = + broxton_calc_cdclk(dev_priv, max_pixclk); - return ret; + return 0; } static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) @@ -5955,41 +5944,31 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND); } -static void valleyview_modeset_global_resources(struct drm_atomic_state *old_state) +static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev, NULL); - int req_cdclk; - - /* The path in intel_mode_max_pixclk() with a NULL atomic state should - * never fail. */ - if (WARN_ON(max_pixclk < 0)) - return; - - req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - if (req_cdclk != dev_priv->cdclk_freq) { - /* - * FIXME: We can end up here with all power domains off, yet - * with a CDCLK frequency other than the minimum. To account - * for this take the PIPE-A power domain, which covers the HW - * blocks needed for the following programming. This can be - * removed once it's guaranteed that we get here either with - * the minimum CDCLK set, or the required power domains - * enabled. - */ - intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A); + /* + * FIXME: We can end up here with all power domains off, yet + * with a CDCLK frequency other than the minimum. To account + * for this take the PIPE-A power domain, which covers the HW + * blocks needed for the following programming. This can be + * removed once it's guaranteed that we get here either with + * the minimum CDCLK set, or the required power domains + * enabled. + */ + intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A); - if (IS_CHERRYVIEW(dev)) - cherryview_set_cdclk(dev, req_cdclk); - else - valleyview_set_cdclk(dev, req_cdclk); + if (IS_CHERRYVIEW(dev)) + cherryview_set_cdclk(dev, req_cdclk); + else + valleyview_set_cdclk(dev, req_cdclk); - vlv_program_pfi_credits(dev_priv); + vlv_program_pfi_credits(dev_priv); - intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A); - } + intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A); } static void valleyview_crtc_enable(struct drm_crtc *crtc) @@ -9490,41 +9469,35 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) intel_prepare_ddi(dev); } -static void broxton_modeset_global_resources(struct drm_atomic_state *old_state) +static void broxton_modeset_commit_cdclk(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev, NULL); - int req_cdclk; - - /* see the comment in valleyview_modeset_global_resources */ - if (WARN_ON(max_pixclk < 0)) - return; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; - req_cdclk = broxton_calc_cdclk(dev_priv, max_pixclk); - - if (req_cdclk != dev_priv->cdclk_freq) - broxton_set_cdclk(dev, req_cdclk); + broxton_set_cdclk(dev, req_cdclk); } /* compute the max rate for new configuration */ -static int ilk_max_pixel_rate(struct drm_i915_private *dev_priv) +static int ilk_max_pixel_rate(struct drm_atomic_state *state) { - struct drm_device *dev = dev_priv->dev; struct intel_crtc *intel_crtc; - struct drm_crtc *crtc; + struct intel_crtc_state *crtc_state; int max_pixel_rate = 0; - int pixel_rate; - for_each_crtc(dev, crtc) { - if (!crtc->state->enable) + for_each_intel_crtc(state->dev, intel_crtc) { + int pixel_rate; + + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->base.enable) continue; - intel_crtc = to_intel_crtc(crtc); - pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); + pixel_rate = ilk_pipe_pixel_rate(crtc_state); /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (IS_BROADWELL(dev) && intel_crtc->config->ips_enabled) + if (IS_BROADWELL(state->dev) && crtc_state->ips_enabled) pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95); max_pixel_rate = max(max_pixel_rate, pixel_rate); @@ -9610,20 +9583,21 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk) cdclk, dev_priv->cdclk_freq); } -static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, - int max_pixel_rate) +static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state) { + struct drm_i915_private *dev_priv = to_i915(state->dev); + int max_pixclk = ilk_max_pixel_rate(state); int cdclk; /* * FIXME should also account for plane ratio * once 64bpp pixel formats are supported. */ - if (max_pixel_rate > 540000) + if (max_pixclk > 540000) cdclk = 675000; - else if (max_pixel_rate > 450000) + else if (max_pixclk > 450000) cdclk = 540000; - else if (max_pixel_rate > 337500) + else if (max_pixclk > 337500) cdclk = 450000; else cdclk = 337500; @@ -9638,49 +9612,17 @@ static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, cdclk = dev_priv->max_cdclk_freq; } - return cdclk; -} - -static int broadwell_modeset_global_pipes(struct drm_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int max_pixclk = ilk_max_pixel_rate(dev_priv); - int cdclk, i; - - cdclk = broadwell_calc_cdclk(dev_priv, max_pixclk); - - if (cdclk == dev_priv->cdclk_freq) - return 0; - - /* add all active pipes to the state */ - for_each_crtc(state->dev, crtc) { - if (!crtc->state->enable) - continue; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } - - /* disable/enable all currently active pipes while we change cdclk */ - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->enable) - crtc_state->mode_changed = true; + to_intel_atomic_state(state)->cdclk = cdclk; return 0; } -static void broadwell_modeset_global_resources(struct drm_atomic_state *state) +static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixel_rate = ilk_max_pixel_rate(dev_priv); - int req_cdclk = broadwell_calc_cdclk(dev_priv, max_pixel_rate); + struct drm_device *dev = old_state->dev; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; - if (req_cdclk != dev_priv->cdclk_freq) - broadwell_set_cdclk(dev, req_cdclk); + broadwell_set_cdclk(dev, req_cdclk); } static int haswell_crtc_compute_clock(struct intel_crtc *crtc, @@ -13056,10 +12998,41 @@ static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state) return 0; } +static int intel_modeset_all_pipes(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret = 0; + + /* add all active pipes to the state */ + for_each_crtc(state->dev, crtc) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->active || needs_modeset(crtc_state)) + continue; + + crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + break; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + break; + } + + return ret; +} + + /* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; if (!check_digital_port_conflicts(state)) { @@ -13074,15 +13047,19 @@ static int intel_modeset_checks(struct drm_atomic_state *state) * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev) || IS_BROADWELL(dev)) { - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) - ret = valleyview_modeset_global_pipes(state); - else - ret = broadwell_modeset_global_pipes(state); + if (dev_priv->display.modeset_calc_cdclk) { + unsigned int cdclk; - if (ret) + ret = dev_priv->display.modeset_calc_cdclk(state); + + cdclk = to_intel_atomic_state(state)->cdclk; + if (!ret && cdclk != dev_priv->cdclk_freq) + ret = intel_modeset_all_pipes(state); + + if (ret < 0) return ret; - } + } else + to_intel_atomic_state(state)->cdclk = dev_priv->cdclk_freq; intel_modeset_clear_plls(state); @@ -13149,7 +13126,9 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; - } + } else + to_intel_atomic_state(state)->cdclk = + to_i915(state->dev)->cdclk_freq; return drm_atomic_helper_check_planes(state->dev, state); } @@ -13717,7 +13696,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state dev = intel_crtc->base.dev; dev_priv = dev->dev_private; crtc_clock = crtc_state->base.adjusted_mode.crtc_clock; - cdclk = dev_priv->display.get_display_clock_speed(dev); + cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk; if (!crtc_clock || !cdclk) return DRM_PLANE_HELPER_NO_SCALING; @@ -14786,15 +14765,22 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; - if (IS_BROADWELL(dev)) - dev_priv->display.modeset_global_resources = - broadwell_modeset_global_resources; + if (IS_BROADWELL(dev)) { + dev_priv->display.modeset_commit_cdclk = + broadwell_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + broadwell_modeset_calc_cdclk; + } } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.modeset_global_resources = - valleyview_modeset_global_resources; + dev_priv->display.modeset_commit_cdclk = + valleyview_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + valleyview_modeset_calc_cdclk; } else if (IS_BROXTON(dev)) { - dev_priv->display.modeset_global_resources = - broxton_modeset_global_resources; + dev_priv->display.modeset_commit_cdclk = + broxton_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + broxton_modeset_calc_cdclk; } switch (INTEL_INFO(dev)->gen) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d48b98014080d1ab85836cbf0c866f9a8eccb398..853bfd98ef725808bef68a9198bffb09d4d39367 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -244,6 +244,7 @@ typedef struct dpll { struct intel_atomic_state { struct drm_atomic_state base; + unsigned int cdclk; bool dpll_set; struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; };