Skip to content

Commit

Permalink
Merge tag 'drm-intel-fixes-2014-08-21' of git://anongit.freedesktop.o…
Browse files Browse the repository at this point in the history
…rg/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()
  • Loading branch information
Dave Airlie committed Aug 21, 2014
2 parents c3735ae + 1a125d8 commit 20a984c
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 55 deletions.
33 changes: 33 additions & 0 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
33 changes: 12 additions & 21 deletions drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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));

Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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);

Expand Down
7 changes: 6 additions & 1 deletion drivers/gpu/drm/i915/intel_crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
39 changes: 15 additions & 24 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -8502,10 +8500,14 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
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;
}

/*
Expand Down Expand Up @@ -8574,15 +8576,11 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
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);
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;

/*
Expand Down
33 changes: 28 additions & 5 deletions drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -4076,15 +4094,19 @@ 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) {
DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n", intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
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 */
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 20a984c

Please sign in to comment.