diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 55c9663ef2b..f624c611dde 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1032,11 +1032,18 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) struct drm_connector *connector; const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; uint32_t unplug_mask, plug_mask, change_mask; - uint32_t hpd0, hpd1 = 0; + uint32_t hpd0, hpd1; - hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); + spin_lock_irq(&dev_priv->hpd_state.lock); + hpd0 = dev_priv->hpd_state.hpd0_bits; + dev_priv->hpd_state.hpd0_bits = 0; + hpd1 = dev_priv->hpd_state.hpd1_bits; + dev_priv->hpd_state.hpd1_bits = 0; + spin_unlock_irq(&dev_priv->hpd_state.lock); + + hpd0 &= nv_rd32(dev, 0xe050); if (dev_priv->chipset >= 0x90) - hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); + hpd1 &= nv_rd32(dev, 0xe070); plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); @@ -1078,10 +1085,6 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); } - nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); - if (dev_priv->chipset >= 0x90) - nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); - drm_helper_hpd_irq_event(dev); } @@ -1092,8 +1095,22 @@ nv50_display_irq_handler(struct drm_device *dev) uint32_t delayed = 0; if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { - if (!work_pending(&dev_priv->hpd_work)) - queue_work(dev_priv->wq, &dev_priv->hpd_work); + uint32_t hpd0_bits, hpd1_bits = 0; + + hpd0_bits = nv_rd32(dev, 0xe054); + nv_wr32(dev, 0xe054, hpd0_bits); + + if (dev_priv->chipset >= 0x90) { + hpd1_bits = nv_rd32(dev, 0xe074); + nv_wr32(dev, 0xe074, hpd1_bits); + } + + spin_lock(&dev_priv->hpd_state.lock); + dev_priv->hpd_state.hpd0_bits |= hpd0_bits; + dev_priv->hpd_state.hpd1_bits |= hpd1_bits; + spin_unlock(&dev_priv->hpd_state.lock); + + queue_work(dev_priv->wq, &dev_priv->hpd_work); } while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { |