From: Jesse Barnes <jbarnes at virtuousgeek.org> This allows subsequent mode sets to do less work if possible, reducing flicker and speeding up boot time. Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org> --- drivers/gpu/drm/drm_fb_helper.c | 11 ++-- drivers/gpu/drm/i915/intel_display.c | 101 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_dp.c | 20 +++++++ drivers/gpu/drm/i915/intel_fb.c | 4 +- include/drm/drm_fb_helper.h | 2 +- 5 files changed, 129 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 02f04d4..391fc41 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1232,6 +1232,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) struct drm_display_mode **modes; struct drm_encoder *encoder; struct drm_mode_set *modeset; + bool success; bool *enabled; int width, height; int i, ret; @@ -1255,10 +1256,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) drm_enable_connectors(fb_helper, enabled); - if (fb_helper->funcs->initial_config) { - fb_helper->funcs->initial_config(fb_helper, crtcs, modes, - enabled, width, height); - } else { + success = false; + if (fb_helper->funcs->initial_config && + fb_helper->funcs->initial_config(fb_helper, crtcs, modes, + enabled, width, height)) + success = true; + if (!success) { /* clean out all the encoder/crtc combos */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 97f294e..6afe082 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6282,6 +6282,98 @@ static void intel_pch_pll_init(struct drm_device *dev) } } +static int intel_crtc_get_bpp(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipeconf; + int ret; + + pipeconf = PIPECONF(intel_crtc->pipe); + + switch (pipeconf & PIPE_BPC_MASK) { + case PIPE_6BPC: + ret = 18; + break; + case PIPE_8BPC: + ret = 24; + break; + case PIPE_10BPC: + ret = 30; + break; + case PIPE_12BPC: + ret = 36; + break; + default: + ret = 24; + break; + } + + return ret; +} + +static bool intel_crtc_get_status(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int dspcntr, pipeconf; + + dspcntr = DSPCNTR(intel_crtc->plane); + pipeconf = PIPECONF(intel_crtc->pipe); + + if ((I915_READ(dspcntr) & DISPLAY_PLANE_ENABLE) && + (I915_READ(pipeconf) & PIPECONF_ENABLE)) + return true; + + return false; +} + +/* + * Get current mode, encoder, and connector info for this CRTC + */ +static void intel_crtc_get_config(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *mode; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int bpp, w, h, size; + u32 val, pixformat; + bool tiled; + + mode = intel_crtc_mode_get(dev, crtc); + crtc->mode = *mode; + kfree(mode); + crtc->enabled = drm_helper_crtc_in_use(crtc); + + val = I915_READ(DSPCNTR(intel_crtc->plane)); + pixformat = val & DISPPLANE_PIXFORMAT_MASK; + tiled = val & DISPPLANE_TILED; + + switch (pixformat) { + case DISPPLANE_8BPP: + bpp = 1; + break; + case DISPPLANE_15_16BPP: + case DISPPLANE_16BPP: + bpp = 2; + break; + case DISPPLANE_32BPP_NO_ALPHA: + case DISPPLANE_32BPP: + case DISPPLANE_32BPP_30BIT_NO_ALPHA: + bpp = 4; + break; + default: + bpp = 4; /* assume worst case */ + } + + val = I915_READ(PIPESRC(intel_crtc->pipe)); + w = val >> 16; + h = val & 0xffff; + + size = w * h * bpp; +} + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -6314,9 +6406,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; - intel_crtc_reset(&intel_crtc->base); - intel_crtc->active = true; /* force the pipe off on setup_init_config */ - intel_crtc->bpp = 24; /* default for pre-Ironlake */ + intel_crtc->active = intel_crtc_get_status(&intel_crtc->base); + intel_crtc->bpp = intel_crtc_get_bpp(&intel_crtc->base); if (HAS_PCH_SPLIT(dev)) { intel_helper_funcs.prepare = ironlake_crtc_prepare; @@ -6841,6 +6932,7 @@ void intel_modeset_init_hw(struct drm_device *dev) void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; int i, ret; drm_mode_config_init(dev); @@ -6889,6 +6981,9 @@ void intel_modeset_init(struct drm_device *dev) i915_disable_vga(dev); intel_setup_outputs(dev); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + intel_crtc_get_config(crtc); + /* Just in case the BIOS is doing something questionable. */ intel_disable_fbc(dev); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9b2effc..924dc27 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2386,6 +2386,17 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_attach_broadcast_rgb_property(connector); } +static int intel_dp_get_pipe(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + pipe = (I915_READ(intel_dp->output_reg) & DP_PIPE_MASK) >> 30; + + return pipe; +} + void intel_dp_init(struct drm_device *dev, int output_reg) { @@ -2446,6 +2457,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) connector->interlace_allowed = true; connector->doublescan_allowed = 0; + connector->encoder = &intel_encoder->base; drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); @@ -2454,6 +2466,12 @@ intel_dp_init(struct drm_device *dev, int output_reg) intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); + intel_encoder->base.crtc = dev_priv->pipe_to_crtc_mapping[intel_dp_get_pipe(intel_dp)]; + + DRM_DEBUG_KMS("setting dp encoder %p crtc to %p (%d)\n", + &intel_encoder->base, intel_encoder->base.crtc, + intel_encoder->base.crtc->base.id); + /* Set up the DDC bus. */ switch (output_reg) { case DP_A: @@ -2572,4 +2590,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } + + connector->status = intel_dp_detect(connector, 0); } diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 0388677..83d3f7b 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -214,7 +214,7 @@ static struct drm_fb_helper_crtc *intel_fb_helper_crtc(struct drm_fb_helper *fb_ return NULL; } -static void intel_fb_initial_config(struct drm_fb_helper *fb_helper, +static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, struct drm_fb_helper_crtc **crtcs, struct drm_display_mode **modes, bool *enabled, int width, int height) @@ -247,6 +247,8 @@ static void intel_fb_initial_config(struct drm_fb_helper *fb_helper, encoder->crtc->base.id, modes[i] ? modes[i]->name : "off"); } + + return true; } static struct drm_fb_helper_funcs intel_fb_helper_funcs = { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index dd98012..40b0c5c 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -56,7 +56,7 @@ struct drm_fb_helper_funcs { int (*fb_probe)(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes); - void (*initial_config)(struct drm_fb_helper *fb_helper, + bool (*initial_config)(struct drm_fb_helper *fb_helper, struct drm_fb_helper_crtc **crtcs, struct drm_display_mode **modes, bool *enabled, int width, int height); -- 1.7.10