Message ID | 1351698624-26626-5-git-send-email-ville.syrjala@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Oct 31, 2012 at 05:50:17PM +0200, ville.syrjala@linux.intel.com wrote: > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > Split the i9xx clock stuff out from i9xx_compute_clocks(). > > Only compile tested! > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> I'm working on a massive overhaul of the clock computation madness, so that we do all that stuff before we start to touch the hw (and so would finally have a reasonable chance at getting global bw issues right). Current wip pile is at: http://cgit.freedesktop.org/~danvet/drm/log/?h=modeset-rework Until we've figured out what's the best approach I prefere if we keep the churn in this (rather convoluted code) low. -Daniel > --- > drivers/gpu/drm/i915/intel_display.c | 128 ++++++++++++++++++++-------------- > 1 files changed, 75 insertions(+), 53 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 6d3feea..b42637b 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -4557,6 +4557,76 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, > ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); > } > > +static bool i9xx_compute_clocks(struct drm_crtc *crtc, > + struct drm_display_mode *adjusted_mode, > + intel_clock_t *clock, > + bool *has_reduced_clock, > + intel_clock_t *reduced_clock, > + int *refclk, int *num_connectors, bool *is_dp) > +{ > + struct drm_device *dev = crtc->dev; > + struct drm_i915_private *dev_priv = dev->dev_private; > + struct intel_encoder *encoder; > + const intel_limit_t *limit; > + bool ok, is_sdvo = false, is_tv = false, is_lvds = false; > + > + *num_connectors = 0; > + > + for_each_encoder_on_crtc(dev, crtc, encoder) { > + switch (encoder->type) { > + case INTEL_OUTPUT_LVDS: > + is_lvds = true; > + break; > + case INTEL_OUTPUT_SDVO: > + case INTEL_OUTPUT_HDMI: > + is_sdvo = true; > + if (encoder->needs_tv_clock) > + is_tv = true; > + break; > + case INTEL_OUTPUT_TVOUT: > + is_tv = true; > + break; > + case INTEL_OUTPUT_DISPLAYPORT: > + *is_dp = true; > + break; > + } > + > + (*num_connectors)++; > + } > + > + *refclk = i9xx_get_refclk(crtc, *num_connectors); > + > + /* > + * Returns a set of divisors for the desired target clock with the given > + * refclk, or FALSE. The returned values represent the clock equation: > + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. > + */ > + limit = intel_limit(crtc, *refclk); > + ok = limit->find_pll(limit, crtc, adjusted_mode->clock, *refclk, NULL, > + clock); > + if (!ok) > + return false; > + > + if (is_lvds && dev_priv->lvds_downclock_avail) { > + /* > + * Ensure we match the reduced clock's P to the target clock. > + * If the clocks don't match, we can't switch the display clock > + * by using the FP0/FP1. In such case we will disable the LVDS > + * downclock feature. > + */ > + *has_reduced_clock = limit->find_pll(limit, crtc, > + dev_priv->lvds_downclock, > + *refclk, > + clock, > + reduced_clock); > + } > + > + if (is_sdvo && is_tv) > + i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock); > + > + return true; > +} > + > static int i9xx_crtc_mode_set(struct drm_crtc *crtc, > struct drm_display_mode *mode, > struct drm_display_mode *adjusted_mode, > @@ -4571,44 +4641,13 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, > int refclk, num_connectors = 0; > intel_clock_t clock, reduced_clock; > u32 dspcntr, pipeconf; > - bool ok, has_reduced_clock = false, is_sdvo = false; > - bool is_lvds = false, is_tv = false, is_dp = false; > - struct intel_encoder *encoder; > - const intel_limit_t *limit; > + bool ok, has_reduced_clock = false; > + bool is_dp = false; > int ret; > > - for_each_encoder_on_crtc(dev, crtc, encoder) { > - switch (encoder->type) { > - case INTEL_OUTPUT_LVDS: > - is_lvds = true; > - break; > - case INTEL_OUTPUT_SDVO: > - case INTEL_OUTPUT_HDMI: > - is_sdvo = true; > - if (encoder->needs_tv_clock) > - is_tv = true; > - break; > - case INTEL_OUTPUT_TVOUT: > - is_tv = true; > - break; > - case INTEL_OUTPUT_DISPLAYPORT: > - is_dp = true; > - break; > - } > - > - num_connectors++; > - } > - > - refclk = i9xx_get_refclk(crtc, num_connectors); > - > - /* > - * Returns a set of divisors for the desired target clock with the given > - * refclk, or FALSE. The returned values represent the clock equation: > - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. > - */ > - limit = intel_limit(crtc, refclk); > - ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL, > - &clock); > + ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock, > + &has_reduced_clock, &reduced_clock, > + &refclk, &num_connectors, &is_dp); > if (!ok) { > DRM_ERROR("Couldn't find PLL settings for mode!\n"); > return -EINVAL; > @@ -4617,23 +4656,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, > /* Ensure that the cursor is valid for the new mode before changing... */ > intel_crtc_update_cursor(crtc, true); > > - if (is_lvds && dev_priv->lvds_downclock_avail) { > - /* > - * Ensure we match the reduced clock's P to the target clock. > - * If the clocks don't match, we can't switch the display clock > - * by using the FP0/FP1. In such case we will disable the LVDS > - * downclock feature. > - */ > - has_reduced_clock = limit->find_pll(limit, crtc, > - dev_priv->lvds_downclock, > - refclk, > - &clock, > - &reduced_clock); > - } > - > - if (is_sdvo && is_tv) > - i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); > - > if (IS_GEN2(dev)) > i8xx_update_pll(crtc, adjusted_mode, &clock, > has_reduced_clock ? &reduced_clock : NULL, > -- > 1.7.8.6 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Wed, Oct 31, 2012 at 05:28:40PM +0100, Daniel Vetter wrote: > On Wed, Oct 31, 2012 at 05:50:17PM +0200, ville.syrjala@linux.intel.com wrote: > > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > > > Split the i9xx clock stuff out from i9xx_compute_clocks(). > > > > Only compile tested! > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > > I'm working on a massive overhaul of the clock computation madness, so > that we do all that stuff before we start to touch the hw (and so would > finally have a reasonable chance at getting global bw issues right). I was sure that the compute_clock() funcs already satisfied that. Perhaps I didn't look hard enough. The reason for this patch actually was that I'm already using that approach in the atomic modeset code. Ie. I call compute_clock() for all modified CRTCs before touching the hardware. Or is the problem simply that multiple calls to compute_clock() would depend on some bit of state that is changed somewhere later in crtc_mode_set()? So that when doing a multi-CRTC modeset, the final state is never seen by any of the compute_clock() funcs when used this way?
On Wed, Oct 31, 2012 at 07:04:29PM +0200, Ville Syrjälä wrote: > On Wed, Oct 31, 2012 at 05:28:40PM +0100, Daniel Vetter wrote: > > On Wed, Oct 31, 2012 at 05:50:17PM +0200, ville.syrjala@linux.intel.com wrote: > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > > > > > Split the i9xx clock stuff out from i9xx_compute_clocks(). > > > > > > Only compile tested! > > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > > > > I'm working on a massive overhaul of the clock computation madness, so > > that we do all that stuff before we start to touch the hw (and so would > > finally have a reasonable chance at getting global bw issues right). > > I was sure that the compute_clock() funcs already satisfied that. > Perhaps I didn't look hard enough. > > The reason for this patch actually was that I'm already using that > approach in the atomic modeset code. Ie. I call compute_clock() for > all modified CRTCs before touching the hardware. > > Or is the problem simply that multiple calls to compute_clock() would > depend on some bit of state that is changed somewhere later in > crtc_mode_set()? So that when doing a multi-CRTC modeset, the final > state is never seen by any of the compute_clock() funcs when used this > way? Well the plan is to compute all this state into struct intel_crtc_config and then switch the code that changes the hw state to only use that precomputed configuration instead of recomputing it. The reason for that intermediate state keeping is twofold: - We need to have some much better notion of a pipe configuration for fastboot anyway (including things like pll sharing and exact dotclocks). Using the same data structure for both the hw readout code needed for fastboot and in our own modeset code should allow for some nice consistency checks. - We have a bunch of rippling dependencies in our state computation, e.g. depending upon global configuration we have different amounts of bandwidth available, which (should) affect the pipe bpp and so the clocks we select, in turn having effects on how we can share plls. If we try to run these computations twice, once in the ->check callback and once when changing the hw state we'll never get a perfect match. Hence I want to precompute and store all values into that pipe_config. Essentially that branch is trying to implement all the atomic modeset stuff without actually having an atomic modeset ioctl ;-) My aim is that in the end I can detect fdi b/c link sharing constraints, dither the other pipe to a lower pipe_bpp, add it to the array of pipe that need a full modeset and then enable everything. Also, while I'm at it a want to kill all these messy layering inversions where the crtc code pokes around in various encoders ... It's not quite there yet ;-) Cheers, Daniel
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6d3feea..b42637b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4557,6 +4557,76 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); } +static bool i9xx_compute_clocks(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, + bool *has_reduced_clock, + intel_clock_t *reduced_clock, + int *refclk, int *num_connectors, bool *is_dp) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + const intel_limit_t *limit; + bool ok, is_sdvo = false, is_tv = false, is_lvds = false; + + *num_connectors = 0; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + if (encoder->needs_tv_clock) + is_tv = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + case INTEL_OUTPUT_DISPLAYPORT: + *is_dp = true; + break; + } + + (*num_connectors)++; + } + + *refclk = i9xx_get_refclk(crtc, *num_connectors); + + /* + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ + limit = intel_limit(crtc, *refclk); + ok = limit->find_pll(limit, crtc, adjusted_mode->clock, *refclk, NULL, + clock); + if (!ok) + return false; + + if (is_lvds && dev_priv->lvds_downclock_avail) { + /* + * Ensure we match the reduced clock's P to the target clock. + * If the clocks don't match, we can't switch the display clock + * by using the FP0/FP1. In such case we will disable the LVDS + * downclock feature. + */ + *has_reduced_clock = limit->find_pll(limit, crtc, + dev_priv->lvds_downclock, + *refclk, + clock, + reduced_clock); + } + + if (is_sdvo && is_tv) + i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock); + + return true; +} + static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4571,44 +4641,13 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dspcntr, pipeconf; - bool ok, has_reduced_clock = false, is_sdvo = false; - bool is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *encoder; - const intel_limit_t *limit; + bool ok, has_reduced_clock = false; + bool is_dp = false; int ret; - for_each_encoder_on_crtc(dev, crtc, encoder) { - switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; - case INTEL_OUTPUT_SDVO: - case INTEL_OUTPUT_HDMI: - is_sdvo = true; - if (encoder->needs_tv_clock) - is_tv = true; - break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; - } - - num_connectors++; - } - - refclk = i9xx_get_refclk(crtc, num_connectors); - - /* - * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. - */ - limit = intel_limit(crtc, refclk); - ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL, - &clock); + ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock, + &has_reduced_clock, &reduced_clock, + &refclk, &num_connectors, &is_dp); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); return -EINVAL; @@ -4617,23 +4656,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - if (is_lvds && dev_priv->lvds_downclock_avail) { - /* - * Ensure we match the reduced clock's P to the target clock. - * If the clocks don't match, we can't switch the display clock - * by using the FP0/FP1. In such case we will disable the LVDS - * downclock feature. - */ - has_reduced_clock = limit->find_pll(limit, crtc, - dev_priv->lvds_downclock, - refclk, - &clock, - &reduced_clock); - } - - if (is_sdvo && is_tv) - i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); - if (IS_GEN2(dev)) i8xx_update_pll(crtc, adjusted_mode, &clock, has_reduced_clock ? &reduced_clock : NULL,