Currently only containing the requested and the adjusted mode. And only crtc callbacks are converted somewhat to it, encoders will be done on a as-needed basis (simply too much churn in one patch otherwise). Future patches will add tons more useful stuff to this struct, starting with the very simple. v2: Store the pipe_config in the intel_crtc, so that the ->mode-set, ->enable and also ->disable have easy access to it. v3: Store the pipe config in the right crtc ... v4: Rebased. v5: Fixup an BUG when trying to kfree an ERR_PTR. Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch> --- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/intel_display.c | 84 +++++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 7 +++ 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0f1d15b..1196d0e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -271,6 +271,8 @@ struct drm_i915_error_state { struct intel_display_error_state *display; }; +struct intel_crtc_config; + struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); @@ -284,8 +286,6 @@ struct drm_i915_display_funcs { struct drm_display_mode *mode); void (*modeset_global_resources)(struct drm_device *dev); int (*crtc_mode_set)(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); void (*crtc_enable)(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6fe4d07..d2f5e7fd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3881,15 +3881,15 @@ bool intel_connector_get_hw_state(struct intel_connector *connector) return encoder->get_hw_state(encoder, &pipe); } -static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool intel_crtc_compute_config(struct drm_crtc *crtc, + struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->dev; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ - if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4) + if (pipe_config->requested_mode.clock * 3 > IRONLAKE_FDI_FREQ * 4) return false; } @@ -4579,14 +4579,15 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, } static int i9xx_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int refclk, num_connectors = 0; @@ -5484,14 +5485,15 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, } static int ironlake_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; @@ -5650,14 +5652,15 @@ static void haswell_modeset_global_resources(struct drm_device *dev) } static int haswell_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; @@ -5732,8 +5735,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, } static int intel_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { @@ -5742,6 +5743,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_encoder_helper_funcs *encoder_funcs; struct intel_encoder *encoder; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int ret; @@ -5752,8 +5756,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, drm_vblank_pre_modeset(dev, pipe); - ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, - x, y, fb); + ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb); + drm_vblank_post_modeset(dev, pipe); if (ret != 0) @@ -7382,19 +7386,24 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) } } -static struct drm_display_mode * -intel_modeset_adjusted_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode) +static struct intel_crtc_config * +intel_modeset_pipe_config(struct drm_crtc *crtc, + struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; - struct drm_display_mode *adjusted_mode; struct drm_encoder_helper_funcs *encoder_funcs; struct intel_encoder *encoder; + struct intel_crtc_config *pipe_config; - adjusted_mode = drm_mode_duplicate(dev, mode); - if (!adjusted_mode) + pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); + if (!pipe_config) return ERR_PTR(-ENOMEM); + pipe_config->adjusted_mode = *mode; + pipe_config->adjusted_mode.base.id = 0; + pipe_config->requested_mode = *mode; + pipe_config->requested_mode.base.id = 0; + /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. @@ -7405,22 +7414,23 @@ intel_modeset_adjusted_mode(struct drm_crtc *crtc, if (&encoder->new_crtc->base != crtc) continue; encoder_funcs = encoder->base.helper_private; - if (!(encoder_funcs->mode_fixup(&encoder->base, mode, - adjusted_mode))) { + if (!(encoder_funcs->mode_fixup(&encoder->base, + &pipe_config->requested_mode, + &pipe_config->adjusted_mode))) { DRM_DEBUG_KMS("Encoder fixup failed\n"); goto fail; } } - if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) { + if (!(intel_crtc_compute_config(crtc, pipe_config))) { DRM_DEBUG_KMS("CRTC fixup failed\n"); goto fail; } DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - return adjusted_mode; + return pipe_config; fail: - drm_mode_destroy(dev, adjusted_mode); + kfree(pipe_config); return ERR_PTR(-EINVAL); } @@ -7686,7 +7696,8 @@ int intel_set_mode(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode; + struct drm_display_mode *saved_mode, *saved_hwmode; + struct intel_crtc_config *pipe_config; struct intel_crtc *intel_crtc; unsigned disable_pipes, prepare_pipes, modeset_pipes; int ret = 0; @@ -7713,11 +7724,13 @@ int intel_set_mode(struct drm_crtc *crtc, * Hence simply check whether any bit is set in modeset_pipes in all the * pieces of code that are not yet converted to deal with mutliple crtcs * changing their mode at the same time. */ - adjusted_mode = NULL; + pipe_config = NULL; if (modeset_pipes) { - adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); - if (IS_ERR(adjusted_mode)) { - ret = PTR_ERR(adjusted_mode); + pipe_config = intel_modeset_pipe_config(crtc, mode); + if (IS_ERR(pipe_config)) { + ret = PTR_ERR(pipe_config); + pipe_config = NULL; + goto out; } } @@ -7730,8 +7743,12 @@ int intel_set_mode(struct drm_crtc *crtc, /* crtc->mode is already used by the ->mode_set callbacks, hence we need * to set it here already despite that we pass it down the callchain. */ - if (modeset_pipes) + if (modeset_pipes) { crtc->mode = *mode; + /* mode_set/enable/disable functions rely on a correct pipe + * config. */ + to_intel_crtc(crtc)->config = *pipe_config; + } /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ @@ -7745,7 +7762,6 @@ int intel_set_mode(struct drm_crtc *crtc, */ for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { ret = intel_crtc_mode_set(&intel_crtc->base, - mode, adjusted_mode, x, y, fb); if (ret) goto done; @@ -7757,7 +7773,7 @@ int intel_set_mode(struct drm_crtc *crtc, if (modeset_pipes) { /* Store real post-adjustment hardware mode. */ - crtc->hwmode = *adjusted_mode; + crtc->hwmode = pipe_config->adjusted_mode; /* Calculate and store various constants which * are later needed by vblank and swap-completion @@ -7768,7 +7784,6 @@ int intel_set_mode(struct drm_crtc *crtc, /* FIXME: add subpixel order */ done: - drm_mode_destroy(dev, adjusted_mode); if (ret && crtc->enabled) { crtc->hwmode = *saved_hwmode; crtc->mode = *saved_mode; @@ -7777,6 +7792,7 @@ done: } out: + kfree(pipe_config); kfree(saved_mode); return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 13afb37..898fdfe 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -199,6 +199,11 @@ struct intel_connector { struct edid *edid; }; +struct intel_crtc_config { + struct drm_display_mode requested_mode; + struct drm_display_mode adjusted_mode; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -232,6 +237,8 @@ struct intel_crtc { bool cursor_visible; unsigned int bpp; + struct intel_crtc_config config; + /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; uint32_t ddi_pll_sel; -- 1.7.11.4