mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 23:51:39 +00:00
Merge tag 'drm-intel-fixes-2014-08-21' of git://anongit.freedesktop.org/drm-intel
Display fixes from Ville and Imre, all cc: stable. * tag 'drm-intel-fixes-2014-08-21' of git://anongit.freedesktop.org/drm-intel: drm/i915: don't try to retrain a DP link on an inactive CRTC drm/i915: make sure VDD is turned off during system suspend drm/i915: cancel hotplug and dig_port work during suspend and unload drm/i915: fix HPD IRQ reenable work cancelation drm/i915: take display port power domain in DP HPD handler drm/i915: Don't try to enable cursor from setplane when crtc is disabled drm/i915: Skip load detect when intel_crtc->new_enable==true drm/i915: Fix locking for intel_enable_pipe_a()
This commit is contained in:
commit
20a984c2a5
@ -494,6 +494,36 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
|
||||
dev_priv->long_hpd_port_mask = 0;
|
||||
dev_priv->short_hpd_port_mask = 0;
|
||||
dev_priv->hpd_event_bits = 0;
|
||||
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
|
||||
cancel_work_sync(&dev_priv->dig_port_work);
|
||||
cancel_work_sync(&dev_priv->hotplug_work);
|
||||
cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work);
|
||||
}
|
||||
|
||||
static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
||||
|
||||
if (intel_encoder->suspend)
|
||||
intel_encoder->suspend(intel_encoder);
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
|
||||
static int i915_drm_freeze(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -538,6 +568,9 @@ static int i915_drm_freeze(struct drm_device *dev)
|
||||
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
|
||||
|
||||
intel_runtime_pm_disable_interrupts(dev);
|
||||
intel_hpd_cancel_work(dev_priv);
|
||||
|
||||
intel_suspend_encoders(dev_priv);
|
||||
|
||||
intel_suspend_gt_powersave(dev);
|
||||
|
||||
|
@ -1458,7 +1458,7 @@ struct drm_i915_private {
|
||||
} hpd_mark;
|
||||
} hpd_stats[HPD_NUM_PINS];
|
||||
u32 hpd_event_bits;
|
||||
struct timer_list hotplug_reenable_timer;
|
||||
struct delayed_work hotplug_reenable_work;
|
||||
|
||||
struct i915_fbc fbc;
|
||||
struct i915_drrs drrs;
|
||||
@ -2178,6 +2178,7 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
|
||||
extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
|
||||
extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
|
||||
int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
|
||||
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
|
||||
|
||||
extern void intel_console_resume(struct work_struct *work);
|
||||
|
||||
|
@ -1189,8 +1189,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
||||
* some connectors */
|
||||
if (hpd_disabled) {
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
mod_timer(&dev_priv->hotplug_reenable_timer,
|
||||
jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
|
||||
mod_delayed_work(system_wq, &dev_priv->hotplug_reenable_work,
|
||||
msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
@ -1213,11 +1213,6 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
||||
drm_kms_helper_hotplug_event(dev);
|
||||
}
|
||||
|
||||
static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
del_timer_sync(&dev_priv->hotplug_reenable_timer);
|
||||
}
|
||||
|
||||
static void ironlake_rps_change_irq_handler(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -3892,8 +3887,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
intel_hpd_irq_uninstall(dev_priv);
|
||||
|
||||
gen8_irq_reset(dev);
|
||||
}
|
||||
|
||||
@ -3908,8 +3901,6 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
|
||||
|
||||
I915_WRITE(VLV_MASTER_IER, 0);
|
||||
|
||||
intel_hpd_irq_uninstall(dev_priv);
|
||||
|
||||
for_each_pipe(pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0xffff);
|
||||
|
||||
@ -3988,8 +3979,6 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
intel_hpd_irq_uninstall(dev_priv);
|
||||
|
||||
ironlake_irq_reset(dev);
|
||||
}
|
||||
|
||||
@ -4360,8 +4349,6 @@ static void i915_irq_uninstall(struct drm_device * dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipe;
|
||||
|
||||
intel_hpd_irq_uninstall(dev_priv);
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
@ -4598,8 +4585,6 @@ static void i965_irq_uninstall(struct drm_device * dev)
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
intel_hpd_irq_uninstall(dev_priv);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
|
||||
@ -4615,14 +4600,18 @@ static void i965_irq_uninstall(struct drm_device * dev)
|
||||
I915_WRITE(IIR, I915_READ(IIR));
|
||||
}
|
||||
|
||||
static void intel_hpd_irq_reenable(unsigned long data)
|
||||
static void intel_hpd_irq_reenable(struct work_struct *work)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = (struct drm_i915_private *)data;
|
||||
struct drm_i915_private *dev_priv =
|
||||
container_of(work, typeof(*dev_priv),
|
||||
hotplug_reenable_work.work);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
unsigned long irqflags;
|
||||
int i;
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
|
||||
for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) {
|
||||
struct drm_connector *connector;
|
||||
@ -4648,6 +4637,8 @@ static void intel_hpd_irq_reenable(unsigned long data)
|
||||
if (dev_priv->display.hpd_irq_setup)
|
||||
dev_priv->display.hpd_irq_setup(dev);
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
void intel_irq_init(struct drm_device *dev)
|
||||
@ -4670,8 +4661,8 @@ void intel_irq_init(struct drm_device *dev)
|
||||
setup_timer(&dev_priv->gpu_error.hangcheck_timer,
|
||||
i915_hangcheck_elapsed,
|
||||
(unsigned long) dev);
|
||||
setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable,
|
||||
(unsigned long) dev_priv);
|
||||
INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work,
|
||||
intel_hpd_irq_reenable);
|
||||
|
||||
pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
|
||||
|
||||
|
@ -699,16 +699,21 @@ intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
goto out;
|
||||
}
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
/* for pre-945g platforms use load detect */
|
||||
if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) {
|
||||
if (intel_crt_detect_ddc(connector))
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = intel_crt_load_detect(crt);
|
||||
intel_release_load_detect_pipe(connector, &tmp, &ctx);
|
||||
intel_release_load_detect_pipe(connector, &tmp);
|
||||
} else
|
||||
status = connector_status_unknown;
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
out:
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
return status;
|
||||
|
@ -8462,8 +8462,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
connector->base.id, connector->name,
|
||||
encoder->base.id, encoder->name);
|
||||
|
||||
drm_modeset_acquire_init(ctx, 0);
|
||||
|
||||
retry:
|
||||
ret = drm_modeset_lock(&config->connection_mutex, ctx);
|
||||
if (ret)
|
||||
@ -8502,10 +8500,14 @@ retry:
|
||||
i++;
|
||||
if (!(encoder->possible_crtcs & (1 << i)))
|
||||
continue;
|
||||
if (!possible_crtc->enabled) {
|
||||
crtc = possible_crtc;
|
||||
break;
|
||||
}
|
||||
if (possible_crtc->enabled)
|
||||
continue;
|
||||
/* This can occur when applying the pipe A quirk on resume. */
|
||||
if (to_intel_crtc(possible_crtc)->new_enabled)
|
||||
continue;
|
||||
|
||||
crtc = possible_crtc;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -8574,15 +8576,11 @@ fail_unlock:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
drm_modeset_drop_locks(ctx);
|
||||
drm_modeset_acquire_fini(ctx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void intel_release_load_detect_pipe(struct drm_connector *connector,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
struct intel_load_detect_pipe *old)
|
||||
{
|
||||
struct intel_encoder *intel_encoder =
|
||||
intel_attached_encoder(connector);
|
||||
@ -8606,17 +8604,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
|
||||
drm_framebuffer_unreference(old->release_fb);
|
||||
}
|
||||
|
||||
goto unlock;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Switch crtc and encoder back off if necessary */
|
||||
if (old->dpms_mode != DRM_MODE_DPMS_ON)
|
||||
connector->funcs->dpms(connector, old->dpms_mode);
|
||||
|
||||
unlock:
|
||||
drm_modeset_drop_locks(ctx);
|
||||
drm_modeset_acquire_fini(ctx);
|
||||
}
|
||||
|
||||
static int i9xx_pll_refclk(struct drm_device *dev,
|
||||
@ -11700,8 +11693,8 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
};
|
||||
const struct drm_rect clip = {
|
||||
/* integer pixels */
|
||||
.x2 = intel_crtc->config.pipe_src_w,
|
||||
.y2 = intel_crtc->config.pipe_src_h,
|
||||
.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0,
|
||||
.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0,
|
||||
};
|
||||
bool visible;
|
||||
int ret;
|
||||
@ -12659,7 +12652,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
|
||||
struct intel_connector *connector;
|
||||
struct drm_connector *crt = NULL;
|
||||
struct intel_load_detect_pipe load_detect_temp;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx;
|
||||
|
||||
/* We can't just switch on the pipe A, we need to set things up with a
|
||||
* proper mode and output configuration. As a gross hack, enable pipe A
|
||||
@ -12676,10 +12669,8 @@ static void intel_enable_pipe_a(struct drm_device *dev)
|
||||
if (!crt)
|
||||
return;
|
||||
|
||||
if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, &ctx))
|
||||
intel_release_load_detect_pipe(crt, &load_detect_temp, &ctx);
|
||||
|
||||
|
||||
if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx))
|
||||
intel_release_load_detect_pipe(crt, &load_detect_temp);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -13112,7 +13103,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
||||
* experience fancy races otherwise.
|
||||
*/
|
||||
drm_irq_uninstall(dev);
|
||||
cancel_work_sync(&dev_priv->hotplug_work);
|
||||
intel_hpd_cancel_work(dev_priv);
|
||||
dev_priv->pm._irqs_disabled = true;
|
||||
|
||||
/*
|
||||
|
@ -3553,6 +3553,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
|
||||
if (WARN_ON(!intel_encoder->base.crtc))
|
||||
return;
|
||||
|
||||
if (!to_intel_crtc(intel_encoder->base.crtc)->active)
|
||||
return;
|
||||
|
||||
/* Try to read receiver status if the link appears to be up */
|
||||
if (!intel_dp_get_link_status(intel_dp, link_status)) {
|
||||
return;
|
||||
@ -4003,6 +4006,16 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
|
||||
kfree(intel_dig_port);
|
||||
}
|
||||
|
||||
static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
return;
|
||||
|
||||
edp_panel_vdd_off_sync(intel_dp);
|
||||
}
|
||||
|
||||
static void intel_dp_encoder_reset(struct drm_encoder *encoder)
|
||||
{
|
||||
intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder));
|
||||
@ -4037,15 +4050,21 @@ bool
|
||||
intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
|
||||
{
|
||||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct intel_encoder *intel_encoder = &intel_dig_port->base;
|
||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
enum intel_display_power_domain power_domain;
|
||||
bool ret = true;
|
||||
|
||||
if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
|
||||
intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
|
||||
DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
|
||||
long_hpd ? "long" : "short");
|
||||
|
||||
power_domain = intel_display_port_power_domain(intel_encoder);
|
||||
intel_display_power_get(dev_priv, power_domain);
|
||||
|
||||
if (long_hpd) {
|
||||
if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
|
||||
goto mst_fail;
|
||||
@ -4061,8 +4080,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
|
||||
|
||||
} else {
|
||||
if (intel_dp->is_mst) {
|
||||
ret = intel_dp_check_mst_status(intel_dp);
|
||||
if (ret == -EINVAL)
|
||||
if (intel_dp_check_mst_status(intel_dp) == -EINVAL)
|
||||
goto mst_fail;
|
||||
}
|
||||
|
||||
@ -4076,7 +4094,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
|
||||
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
ret = false;
|
||||
goto put_power;
|
||||
mst_fail:
|
||||
/* if we were in MST mode, and device is not there get out of MST mode */
|
||||
if (intel_dp->is_mst) {
|
||||
@ -4084,7 +4103,10 @@ mst_fail:
|
||||
intel_dp->is_mst = false;
|
||||
drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
|
||||
}
|
||||
return true;
|
||||
put_power:
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return which DP Port should be selected for Transcoder DP control */
|
||||
@ -4722,6 +4744,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
|
||||
intel_encoder->disable = intel_disable_dp;
|
||||
intel_encoder->get_hw_state = intel_dp_get_hw_state;
|
||||
intel_encoder->get_config = intel_dp_get_config;
|
||||
intel_encoder->suspend = intel_dp_encoder_suspend;
|
||||
if (IS_CHERRYVIEW(dev)) {
|
||||
intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
|
||||
intel_encoder->pre_enable = chv_pre_enable_dp;
|
||||
|
@ -153,6 +153,12 @@ struct intel_encoder {
|
||||
* be set correctly before calling this function. */
|
||||
void (*get_config)(struct intel_encoder *,
|
||||
struct intel_crtc_config *pipe_config);
|
||||
/*
|
||||
* Called during system suspend after all pending requests for the
|
||||
* encoder are flushed (for example for DP AUX transactions) and
|
||||
* device interrupts are disabled.
|
||||
*/
|
||||
void (*suspend)(struct intel_encoder *);
|
||||
int crtc_mask;
|
||||
enum hpd_pin hpd_pin;
|
||||
};
|
||||
@ -830,8 +836,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
void intel_release_load_detect_pipe(struct drm_connector *connector,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
struct intel_load_detect_pipe *old);
|
||||
int intel_pin_and_fence_fb_obj(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj,
|
||||
struct intel_engine_cs *pipelined);
|
||||
|
@ -1323,11 +1323,16 @@ intel_tv_detect(struct drm_connector *connector, bool force)
|
||||
struct intel_load_detect_pipe tmp;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) {
|
||||
type = intel_tv_detect_type(intel_tv, connector);
|
||||
intel_release_load_detect_pipe(connector, &tmp, &ctx);
|
||||
intel_release_load_detect_pipe(connector, &tmp);
|
||||
} else
|
||||
return connector_status_unknown;
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
} else
|
||||
return connector->status;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user