Commit b8cecdf5 authored by Daniel Vetter's avatar Daniel Vetter

drm/i915: introduce struct intel_crtc_config

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 OOPS when trying to kfree an ERR_PTR.

v6: Used drm_moode_copy and some other small cleanups as suggested
by Ville Syrjälä.

v7: drm_mode_copy preserves the mode id of the destination, so no need
to clear it again (Ville).

v8: Break a long line spotted by Paulo.
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarPaulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 7c23396b
...@@ -284,6 +284,8 @@ struct drm_i915_error_state { ...@@ -284,6 +284,8 @@ struct drm_i915_error_state {
struct intel_display_error_state *display; struct intel_display_error_state *display;
}; };
struct intel_crtc_config;
struct drm_i915_display_funcs { struct drm_i915_display_funcs {
bool (*fbc_enabled)(struct drm_device *dev); bool (*fbc_enabled)(struct drm_device *dev);
void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval);
...@@ -297,8 +299,6 @@ struct drm_i915_display_funcs { ...@@ -297,8 +299,6 @@ struct drm_i915_display_funcs {
struct drm_display_mode *mode); struct drm_display_mode *mode);
void (*modeset_global_resources)(struct drm_device *dev); void (*modeset_global_resources)(struct drm_device *dev);
int (*crtc_mode_set)(struct drm_crtc *crtc, int (*crtc_mode_set)(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y, int x, int y,
struct drm_framebuffer *old_fb); struct drm_framebuffer *old_fb);
void (*crtc_enable)(struct drm_crtc *crtc); void (*crtc_enable)(struct drm_crtc *crtc);
......
...@@ -3971,15 +3971,16 @@ bool intel_connector_get_hw_state(struct intel_connector *connector) ...@@ -3971,15 +3971,16 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
return encoder->get_hw_state(encoder, &pipe); return encoder->get_hw_state(encoder, &pipe);
} }
static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, static bool intel_crtc_compute_config(struct drm_crtc *crtc,
const struct drm_display_mode *mode, struct intel_crtc_config *pipe_config)
struct drm_display_mode *adjusted_mode)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */ /* 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; return false;
} }
...@@ -4665,14 +4666,15 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, ...@@ -4665,14 +4666,15 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
} }
static int i9xx_crtc_mode_set(struct drm_crtc *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, int x, int y,
struct drm_framebuffer *fb) struct drm_framebuffer *fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 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 pipe = intel_crtc->pipe;
int plane = intel_crtc->plane; int plane = intel_crtc->plane;
int refclk, num_connectors = 0; int refclk, num_connectors = 0;
...@@ -5637,14 +5639,15 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, ...@@ -5637,14 +5639,15 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
} }
static int ironlake_crtc_mode_set(struct drm_crtc *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, int x, int y,
struct drm_framebuffer *fb) struct drm_framebuffer *fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 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 pipe = intel_crtc->pipe;
int plane = intel_crtc->plane; int plane = intel_crtc->plane;
int num_connectors = 0; int num_connectors = 0;
...@@ -5803,14 +5806,15 @@ static void haswell_modeset_global_resources(struct drm_device *dev) ...@@ -5803,14 +5806,15 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
} }
static int haswell_crtc_mode_set(struct drm_crtc *crtc, 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, int x, int y,
struct drm_framebuffer *fb) struct drm_framebuffer *fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 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 pipe = intel_crtc->pipe;
int plane = intel_crtc->plane; int plane = intel_crtc->plane;
int num_connectors = 0; int num_connectors = 0;
...@@ -5887,8 +5891,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5887,8 +5891,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
} }
static int intel_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, int x, int y,
struct drm_framebuffer *fb) struct drm_framebuffer *fb)
{ {
...@@ -5897,6 +5899,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5897,6 +5899,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder_helper_funcs *encoder_funcs;
struct intel_encoder *encoder; struct intel_encoder *encoder;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 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 pipe = intel_crtc->pipe;
int ret; int ret;
...@@ -5907,8 +5912,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5907,8 +5912,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
drm_vblank_pre_modeset(dev, pipe); drm_vblank_pre_modeset(dev, pipe);
ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb);
x, y, fb);
drm_vblank_post_modeset(dev, pipe); drm_vblank_post_modeset(dev, pipe);
if (ret != 0) if (ret != 0)
...@@ -7530,19 +7535,22 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) ...@@ -7530,19 +7535,22 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
} }
} }
static struct drm_display_mode * static struct intel_crtc_config *
intel_modeset_adjusted_mode(struct drm_crtc *crtc, intel_modeset_pipe_config(struct drm_crtc *crtc,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_display_mode *adjusted_mode;
struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder_helper_funcs *encoder_funcs;
struct intel_encoder *encoder; struct intel_encoder *encoder;
struct intel_crtc_config *pipe_config;
adjusted_mode = drm_mode_duplicate(dev, mode); pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
if (!adjusted_mode) if (!pipe_config)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
drm_mode_copy(&pipe_config->adjusted_mode, mode);
drm_mode_copy(&pipe_config->requested_mode, mode);
/* Pass our mode to the connectors and the CRTC to give them a chance to /* 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 * adjust it according to limitations or connector properties, and also
* a chance to reject the mode entirely. * a chance to reject the mode entirely.
...@@ -7553,22 +7561,23 @@ intel_modeset_adjusted_mode(struct drm_crtc *crtc, ...@@ -7553,22 +7561,23 @@ intel_modeset_adjusted_mode(struct drm_crtc *crtc,
if (&encoder->new_crtc->base != crtc) if (&encoder->new_crtc->base != crtc)
continue; continue;
encoder_funcs = encoder->base.helper_private; encoder_funcs = encoder->base.helper_private;
if (!(encoder_funcs->mode_fixup(&encoder->base, mode, if (!(encoder_funcs->mode_fixup(&encoder->base,
adjusted_mode))) { &pipe_config->requested_mode,
&pipe_config->adjusted_mode))) {
DRM_DEBUG_KMS("Encoder fixup failed\n"); DRM_DEBUG_KMS("Encoder fixup failed\n");
goto fail; 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"); DRM_DEBUG_KMS("CRTC fixup failed\n");
goto fail; goto fail;
} }
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
return adjusted_mode; return pipe_config;
fail: fail:
drm_mode_destroy(dev, adjusted_mode); kfree(pipe_config);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
...@@ -7834,7 +7843,8 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7834,7 +7843,8 @@ int intel_set_mode(struct drm_crtc *crtc,
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
drm_i915_private_t *dev_priv = dev->dev_private; 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 = NULL;
struct intel_crtc *intel_crtc; struct intel_crtc *intel_crtc;
unsigned disable_pipes, prepare_pipes, modeset_pipes; unsigned disable_pipes, prepare_pipes, modeset_pipes;
int ret = 0; int ret = 0;
...@@ -7861,11 +7871,12 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7861,11 +7871,12 @@ int intel_set_mode(struct drm_crtc *crtc,
* Hence simply check whether any bit is set in modeset_pipes in all the * 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 * pieces of code that are not yet converted to deal with mutliple crtcs
* changing their mode at the same time. */ * changing their mode at the same time. */
adjusted_mode = NULL;
if (modeset_pipes) { if (modeset_pipes) {
adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); pipe_config = intel_modeset_pipe_config(crtc, mode);
if (IS_ERR(adjusted_mode)) { if (IS_ERR(pipe_config)) {
ret = PTR_ERR(adjusted_mode); ret = PTR_ERR(pipe_config);
pipe_config = NULL;
goto out; goto out;
} }
} }
...@@ -7878,8 +7889,12 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7878,8 +7889,12 @@ int intel_set_mode(struct drm_crtc *crtc,
/* crtc->mode is already used by the ->mode_set callbacks, hence we need /* 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. * to set it here already despite that we pass it down the callchain.
*/ */
if (modeset_pipes) if (modeset_pipes) {
crtc->mode = *mode; 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 /* Only after disabling all output pipelines that will be changed can we
* update the the output configuration. */ * update the the output configuration. */
...@@ -7893,7 +7908,6 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7893,7 +7908,6 @@ int intel_set_mode(struct drm_crtc *crtc,
*/ */
for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
ret = intel_crtc_mode_set(&intel_crtc->base, ret = intel_crtc_mode_set(&intel_crtc->base,
mode, adjusted_mode,
x, y, fb); x, y, fb);
if (ret) if (ret)
goto done; goto done;
...@@ -7905,7 +7919,7 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7905,7 +7919,7 @@ int intel_set_mode(struct drm_crtc *crtc,
if (modeset_pipes) { if (modeset_pipes) {
/* Store real post-adjustment hardware mode. */ /* Store real post-adjustment hardware mode. */
crtc->hwmode = *adjusted_mode; crtc->hwmode = pipe_config->adjusted_mode;
/* Calculate and store various constants which /* Calculate and store various constants which
* are later needed by vblank and swap-completion * are later needed by vblank and swap-completion
...@@ -7916,7 +7930,6 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7916,7 +7930,6 @@ int intel_set_mode(struct drm_crtc *crtc,
/* FIXME: add subpixel order */ /* FIXME: add subpixel order */
done: done:
drm_mode_destroy(dev, adjusted_mode);
if (ret && crtc->enabled) { if (ret && crtc->enabled) {
crtc->hwmode = *saved_hwmode; crtc->hwmode = *saved_hwmode;
crtc->mode = *saved_mode; crtc->mode = *saved_mode;
...@@ -7925,6 +7938,7 @@ int intel_set_mode(struct drm_crtc *crtc, ...@@ -7925,6 +7938,7 @@ int intel_set_mode(struct drm_crtc *crtc,
} }
out: out:
kfree(pipe_config);
kfree(saved_mode); kfree(saved_mode);
return ret; return ret;
} }
......
...@@ -200,6 +200,11 @@ struct intel_connector { ...@@ -200,6 +200,11 @@ struct intel_connector {
struct edid *edid; struct edid *edid;
}; };
struct intel_crtc_config {
struct drm_display_mode requested_mode;
struct drm_display_mode adjusted_mode;
};
struct intel_crtc { struct intel_crtc {
struct drm_crtc base; struct drm_crtc base;
enum pipe pipe; enum pipe pipe;
...@@ -233,6 +238,8 @@ struct intel_crtc { ...@@ -233,6 +238,8 @@ struct intel_crtc {
bool cursor_visible; bool cursor_visible;
unsigned int bpp; unsigned int bpp;
struct intel_crtc_config config;
/* We can share PLLs across outputs if the timings match */ /* We can share PLLs across outputs if the timings match */
struct intel_pch_pll *pch_pll; struct intel_pch_pll *pch_pll;
uint32_t ddi_pll_sel; uint32_t ddi_pll_sel;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment