drm/nouveau: Implement the vblank DRM hooks.
authorFrancisco Jerez <currojerez@riseup.net>
Thu, 21 Oct 2010 16:19:29 +0000 (18:19 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 3 Dec 2010 05:11:11 +0000 (15:11 +1000)
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_hw.c
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_graph.c

index 2e11fd65b4dd2898335aba8926412a6164496550..f8987bcb7f51be73bbb355be0631266f73a512d2 100644 (file)
@@ -29,6 +29,7 @@
 #include "nouveau_drv.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_hw.h"
 
 static void
 nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
@@ -104,3 +105,29 @@ const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
        .output_poll_changed = nouveau_fbcon_output_poll_changed,
 };
 
+int
+nouveau_vblank_enable(struct drm_device *dev, int crtc)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->card_type >= NV_50)
+               nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
+                       NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
+       else
+               NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
+                           NV_PCRTC_INTR_0_VBLANK);
+
+       return 0;
+}
+
+void
+nouveau_vblank_disable(struct drm_device *dev, int crtc)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->card_type >= NV_50)
+               nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
+                       NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
+       else
+               NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
+}
index 15f48493d0d8835a20a706b2115f1bdc75bd1b1d..52f9307d7396e5df3e06dd94aa1f40dd18398e2f 100644 (file)
@@ -397,6 +397,9 @@ static struct drm_driver driver = {
        .irq_postinstall = nouveau_irq_postinstall,
        .irq_uninstall = nouveau_irq_uninstall,
        .irq_handler = nouveau_irq_handler,
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = nouveau_vblank_enable,
+       .disable_vblank = nouveau_vblank_disable,
        .reclaim_buffers = drm_core_reclaim_buffers,
        .ioctls = nouveau_ioctls,
        .fops = {
@@ -407,6 +410,7 @@ static struct drm_driver driver = {
                .mmap = nouveau_ttm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
+               .read = drm_read,
 #if defined(CONFIG_COMPAT)
                .compat_ioctl = nouveau_compat_ioctl,
 #endif
index a356d894a2eebb3909c6c41895c45ff0a2d56452..7cf034fd5cd0d3126afde130ec220b11bbbdb232 100644 (file)
@@ -1312,6 +1312,10 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
 extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
                                  struct drm_file *);
 
+/* nouveau_display.c */
+int nouveau_vblank_enable(struct drm_device *dev, int crtc);
+void nouveau_vblank_disable(struct drm_device *dev, int crtc);
+
 /* nv10_gpio.c */
 int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
 int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
index 979275836985afa869cb00bf2a051b3a6933c2a8..6ba640e7a7e936df9a7babcc480bbe30d0967260 100644 (file)
@@ -1017,8 +1017,9 @@ nv_load_state_ext(struct drm_device *dev, int head,
 
        NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start);
 
-       /* Setting 1 on this value gives you interrupts for every vblank period. */
-       NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, 0);
+       /* Enable vblank interrupts. */
+       NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0,
+                   (dev->vblank_enabled[head] ? 1 : 0));
        NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK);
 }
 
index 17e2fa86cde7916a88ac576f614b2b3f62be1bdb..f3ae74ef331878a7a4d4a43e135f806f0da62d40 100644 (file)
@@ -1200,11 +1200,15 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
 static void
 nouveau_crtc_irq_handler(struct drm_device *dev, int crtc)
 {
-       if (crtc & 1)
+       if (crtc & 1) {
                nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
+               drm_handle_vblank(dev, 0);
+       }
 
-       if (crtc & 2)
+       if (crtc & 2) {
                nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
+               drm_handle_vblank(dev, 1);
+       }
 }
 
 irqreturn_t
index c5f29f0d18da637653feb6015b1aba02bfd1cc52..d72aa8d19a192308e29d912a537c9976e0c16342 100644 (file)
@@ -669,13 +669,13 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_fifo;
 
-       ret = nouveau_irq_init(dev);
+       ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1);
        if (ret)
-               goto out_display;
+               goto out_vblank;
 
-       ret = drm_vblank_init(dev, 0);
+       ret = nouveau_irq_init(dev);
        if (ret)
-               goto out_irq;
+               goto out_vblank;
 
        /* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
@@ -701,7 +701,8 @@ out_fence:
        nouveau_fence_fini(dev);
 out_irq:
        nouveau_irq_fini(dev);
-out_display:
+out_vblank:
+       drm_vblank_cleanup(dev);
        engine->display.destroy(dev);
 out_fifo:
        if (!nouveau_noaccel)
@@ -772,6 +773,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
        nouveau_mem_vram_fini(dev);
 
        nouveau_irq_fini(dev);
+       drm_vblank_cleanup(dev);
 
        nouveau_pm_fini(dev);
        nouveau_bios_takedown(dev);
index 99871e304d106c46b954388207e41e05cd9ed60b..17b950abf20024f47a92c24bb8b1566237a23d7f 100644 (file)
@@ -428,31 +428,29 @@ static void
 nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan;
-       struct list_head *entry, *tmp;
-
-       list_for_each_safe(entry, tmp, &dev_priv->vbl_waiting) {
-               chan = list_entry(entry, struct nouveau_channel, nvsw.vbl_wait);
+       struct nouveau_channel *chan, *tmp;
 
+       list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
+                                nvsw.vbl_wait) {
                nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
                                                chan->nvsw.vblsem_rval);
                list_del(&chan->nvsw.vbl_wait);
+               drm_vblank_put(dev, crtc);
        }
+
+       drm_handle_vblank(dev, crtc);
 }
 
 static void
 nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
 {
-       intr &= NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
-
        if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
                nv50_display_vblank_crtc_handler(dev, 0);
 
        if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
                nv50_display_vblank_crtc_handler(dev, 1);
 
-       nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, intr, 0x00000000);
-       nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr);
+       nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
 }
 
 static void
index d441308a09cf831b8302cbd5be8f1986ccdca0ae..ac7f62d524bbc776d69bcf09d267a382eae62ea9 100644 (file)
@@ -384,14 +384,7 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
        if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1)
                return -EINVAL;
 
-       if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN_1) &
-                          NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data))) {
-               nv_wr32(dev, NV50_PDISPLAY_INTR_1,
-                            NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data));
-               nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
-                            NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data));
-       }
-
+       drm_vblank_get(dev, data);
        list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);
        return 0;
 }