The intent here is to build enough of the configuration to allow set_config to avoid mode setting if possible. Seems to speed up boot a bit on my Dell E6510; should help other eDP platforms as well. One thing that's missing is creating an initial fb for whatever's display at driver load time. This would involve poking around in the display regs to get the offset and making bo and fb objects for the current framebuffer. -- Jesse Barnes, Intel Open Source Technology Center diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdcf99b..8f25e68 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7637,6 +7637,66 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .page_flip = intel_crtc_page_flip, }; +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->pipe); + 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_display_mode *mode; + + mode = intel_crtc_mode_get(dev, crtc); + crtc->mode = *mode; + kfree(mode); + crtc->enabled = drm_helper_crtc_in_use(crtc); +} + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -7669,9 +7729,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)) { if (pipe == 2 && IS_IVYBRIDGE(dev)) @@ -9091,6 +9150,9 @@ static void i915_disable_vga(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; + struct drm_encoder *encoder; + struct drm_connector *connector; int i, ret; drm_mode_config_init(dev); @@ -9142,6 +9204,9 @@ void intel_modeset_init(struct drm_device *dev) gen6_update_ring_freq(dev_priv); } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + intel_crtc_get_config(crtc); + INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 39eccf9..3e24f0b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2360,6 +2360,26 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_attach_broadcast_rgb_property(connector); } +static struct drm_crtc *intel_dp_get_crtc(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int pipe; + + pipe = (I915_READ(intel_dp->output_reg) & DP_PIPE_MASK) >> 30; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->pipe == pipe) + return crtc; + } + + return NULL; +} + void intel_dp_init(struct drm_device *dev, int output_reg) { @@ -2419,6 +2439,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 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); @@ -2427,6 +2448,8 @@ 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 = intel_dp_get_crtc(&intel_encoder->base); + /* Set up the DDC bus. */ switch (output_reg) { case DP_A: @@ -2538,4 +2561,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); }