drm/nouveau/disp: port vblank handling to event interface
authorBen Skeggs <bskeggs@redhat.com>
Wed, 30 Jan 2013 23:23:34 +0000 (09:23 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 20 Feb 2013 06:00:46 +0000 (16:00 +1000)
This removes the nastiness with the interactions between display and
software engines when handling vblank semaphore release interrupts.

Now, all the semantics are handled in one place (sw) \o/.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
19 files changed:
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/engine/disp/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/core/engine/software/nv50.c
drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
drivers/gpu/drm/nouveau/core/include/engine/disp.h
drivers/gpu/drm/nouveau/core/include/engine/software.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_display.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h

index 6d4cb8aec4de336a1b35989f0c4af1e31f43dde8..ebe37fe5d0fc639cd160bbd83d8f1aa5a979d1c4 100644 (file)
@@ -143,6 +143,7 @@ nouveau-y += core/engine/copy/nvc0.o
 nouveau-y += core/engine/copy/nve0.o
 nouveau-y += core/engine/crypt/nv84.o
 nouveau-y += core/engine/crypt/nv98.o
+nouveau-y += core/engine/disp/base.o
 nouveau-y += core/engine/disp/nv04.o
 nouveau-y += core/engine/disp/nv50.o
 nouveau-y += core/engine/disp/nv84.o
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
new file mode 100644 (file)
index 0000000..7a5cae4
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <engine/disp.h>
+
+void
+_nouveau_disp_dtor(struct nouveau_object *object)
+{
+       struct nouveau_disp *disp = (void *)object;
+       nouveau_event_destroy(&disp->vblank);
+       nouveau_engine_destroy(&disp->base);
+}
+
+int
+nouveau_disp_create_(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, int heads,
+                    const char *intname, const char *extname,
+                    int length, void **pobject)
+{
+       struct nouveau_disp *disp;
+       int ret;
+
+       ret = nouveau_engine_create_(parent, engine, oclass, true,
+                                    intname, extname, length, pobject);
+       disp = *pobject;
+       if (ret)
+               return ret;
+
+       return nouveau_event_create(heads, &disp->vblank);
+}
index 6eaf7257be775eca6a5a62682727646035be9413..05e903f08a3696d0c101e67700be6dc24ebe4a92 100644 (file)
@@ -23,6 +23,8 @@
  */
 
 #include <engine/disp.h>
+
+#include <core/event.h>
 #include <core/class.h>
 
 struct nv04_disp_priv {
@@ -35,12 +37,20 @@ nv04_disp_sclass[] = {
        {},
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+nv04_disp_vblank_enable(struct nouveau_event *event, int head)
+{
+       nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
+}
+
 static void
-nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
+nv04_disp_vblank_disable(struct nouveau_event *event, int head)
 {
-       struct nouveau_disp *disp = &priv->base;
-       if (disp->vblank.notify)
-               disp->vblank.notify(disp->vblank.data, crtc);
+       nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
 }
 
 static void
@@ -51,25 +61,25 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
        u32 crtc1 = nv_rd32(priv, 0x602100);
 
        if (crtc0 & 0x00000001) {
-               nv04_disp_intr_vblank(priv, 0);
+               nouveau_event_trigger(priv->base.vblank, 0);
                nv_wr32(priv, 0x600100, 0x00000001);
        }
 
        if (crtc1 & 0x00000001) {
-               nv04_disp_intr_vblank(priv, 1);
+               nouveau_event_trigger(priv->base.vblank, 1);
                nv_wr32(priv, 0x602100, 0x00000001);
        }
 }
 
 static int
 nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
 {
        struct nv04_disp_priv *priv;
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
+       ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
                                  "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -77,6 +87,9 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_engine(priv)->sclass = nv04_disp_sclass;
        nv_subdev(priv)->intr = nv04_disp_intr;
+       priv->base.vblank->priv = priv;
+       priv->base.vblank->enable = nv04_disp_vblank_enable;
+       priv->base.vblank->disable = nv04_disp_vblank_disable;
        return 0;
 }
 
index ca1a7d76a95b50d87864e95954b20aebd7906f76..0d26f00a2f15a3f20a5aa77b73f208c4596f837e 100644 (file)
@@ -27,7 +27,6 @@
 #include <core/handle.h>
 #include <core/class.h>
 
-#include <engine/software.h>
 #include <engine/disp.h>
 
 #include <subdev/bios.h>
@@ -37,7 +36,6 @@
 #include <subdev/bios/pll.h>
 #include <subdev/timer.h>
 #include <subdev/fb.h>
-#include <subdev/bar.h>
 #include <subdev/clock.h>
 
 #include "nv50.h"
@@ -543,6 +541,18 @@ nv50_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
+static void
+nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
+{
+       nv_mask(event->priv, 0x61002c, (1 << head), (1 << head));
+}
+
+static void
+nv50_disp_base_vblank_disable(struct nouveau_event *event, int head)
+{
+       nv_mask(event->priv, 0x61002c, (1 << head), (0 << head));
+}
+
 static int
 nv50_disp_base_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -559,6 +569,9 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       priv->base.vblank->priv = priv;
+       priv->base.vblank->enable = nv50_disp_base_vblank_enable;
+       priv->base.vblank->disable = nv50_disp_base_vblank_disable;
        return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
 }
 
@@ -756,50 +769,6 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv)
        }
 }
 
-static void
-nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
-{
-       struct nouveau_bar *bar = nouveau_bar(priv);
-       struct nouveau_disp *disp = &priv->base;
-       struct nouveau_software_chan *chan, *temp;
-       unsigned long flags;
-
-       spin_lock_irqsave(&disp->vblank.lock, flags);
-       list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
-               if (chan->vblank.crtc != crtc)
-                       continue;
-
-               if (nv_device(priv)->chipset >= 0xc0) {
-                       nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
-                       bar->flush(bar);
-                       nv_wr32(priv, 0x06000c,
-                               upper_32_bits(chan->vblank.offset));
-                       nv_wr32(priv, 0x060010,
-                               lower_32_bits(chan->vblank.offset));
-                       nv_wr32(priv, 0x060014, chan->vblank.value);
-               } else {
-                       nv_wr32(priv, 0x001704, chan->vblank.channel);
-                       nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
-                       bar->flush(bar);
-                       if (nv_device(priv)->chipset == 0x50) {
-                               nv_wr32(priv, 0x001570, chan->vblank.offset);
-                               nv_wr32(priv, 0x001574, chan->vblank.value);
-                       } else {
-                               nv_wr32(priv, 0x060010, chan->vblank.offset);
-                               nv_wr32(priv, 0x060014, chan->vblank.value);
-                       }
-               }
-
-               list_del(&chan->vblank.head);
-               if (disp->vblank.put)
-                       disp->vblank.put(disp->vblank.data, crtc);
-       }
-       spin_unlock_irqrestore(&disp->vblank.lock, flags);
-
-       if (disp->vblank.notify)
-               disp->vblank.notify(disp->vblank.data, crtc);
-}
-
 static u16
 exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
            struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
@@ -1201,13 +1170,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
        }
 
        if (intr1 & 0x00000004) {
-               nv50_disp_intr_vblank(priv, 0);
+               nouveau_event_trigger(priv->base.vblank, 0);
                nv_wr32(priv, 0x610024, 0x00000004);
                intr1 &= ~0x00000004;
        }
 
        if (intr1 & 0x00000008) {
-               nv50_disp_intr_vblank(priv, 1);
+               nouveau_event_trigger(priv->base.vblank, 1);
                nv_wr32(priv, 0x610024, 0x00000008);
                intr1 &= ~0x00000008;
        }
@@ -1226,7 +1195,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv50_disp_priv *priv;
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+       ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
                                  "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -1242,9 +1211,6 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->dac.power = nv50_dac_power;
        priv->dac.sense = nv50_dac_sense;
        priv->sor.power = nv50_sor_power;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index a6bb931450f16c630dd663ada1186c687800f5b9..fc897181fa38424bf19a3f5e737fc6da1da7781d 100644 (file)
@@ -3,7 +3,9 @@
 
 #include <core/parent.h>
 #include <core/namedb.h>
+#include <core/engctx.h>
 #include <core/ramht.h>
+#include <core/event.h>
 
 #include <engine/dmaobj.h>
 #include <engine/disp.h>
index fc84eacdfbec72da6164d89b4c6f7c730e770623..a2153424605d8df956f29333a066203f24954c1a 100644 (file)
@@ -63,7 +63,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv50_disp_priv *priv;
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+       ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
                                  "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -80,9 +80,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->dac.sense = nv50_dac_sense;
        priv->sor.power = nv50_sor_power;
        priv->sor.hdmi = nv84_hdmi_ctrl;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index ba9dfd4669a2d721b68950ca61aadb87842b0777..a315e28ac17e7629f820fe3795f27f7d14620f64 100644 (file)
@@ -69,7 +69,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv50_disp_priv *priv;
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+       ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
                                  "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -91,9 +91,6 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
        priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
        priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index 5d63902cdeda857f820f3c7c714554bd41be2069..480e2ded95fa0d228cf487764ea616b8ae0bd52a 100644 (file)
@@ -53,7 +53,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv50_disp_priv *priv;
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+       ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
                                  "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -70,9 +70,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->dac.sense = nv50_dac_sense;
        priv->sor.power = nv50_sor_power;
        priv->sor.hdmi = nv84_hdmi_ctrl;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index e9192ca389fa091d5276fcfec39f932542c0b809..718b4f66352e467b1491737441bcb5eb9253c245 100644 (file)
@@ -70,7 +70,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv50_disp_priv *priv;
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+       ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
                                  "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -93,9 +93,6 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
        priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
        priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index 9e38ebff5fb3f38b70c0cb5cb18069027b424cfe..74626e8c020b7193826a8bfaf055a2ba091b87bc 100644 (file)
 #include <core/handle.h>
 #include <core/class.h>
 
-#include <engine/software.h>
 #include <engine/disp.h>
 
 #include <subdev/timer.h>
 #include <subdev/fb.h>
-#include <subdev/bar.h>
 #include <subdev/clock.h>
 
 #include <subdev/bios.h>
@@ -443,6 +441,18 @@ nvd0_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
+static void
+nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
+{
+       nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
+}
+
+static void
+nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head)
+{
+       nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
+}
+
 static int
 nvd0_disp_base_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -459,6 +469,10 @@ nvd0_disp_base_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       priv->base.vblank->priv = priv;
+       priv->base.vblank->enable = nvd0_disp_base_vblank_enable;
+       priv->base.vblank->disable = nvd0_disp_base_vblank_disable;
+
        return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
 }
 
@@ -822,35 +836,6 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
        nv_wr32(priv, 0x6101d0, 0x80000000);
 }
 
-static void
-nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
-{
-       struct nouveau_bar *bar = nouveau_bar(priv);
-       struct nouveau_disp *disp = &priv->base;
-       struct nouveau_software_chan *chan, *temp;
-       unsigned long flags;
-
-       spin_lock_irqsave(&disp->vblank.lock, flags);
-       list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
-               if (chan->vblank.crtc != crtc)
-                       continue;
-
-               nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
-               bar->flush(bar);
-               nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
-               nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
-               nv_wr32(priv, 0x060014, chan->vblank.value);
-
-               list_del(&chan->vblank.head);
-               if (disp->vblank.put)
-                       disp->vblank.put(disp->vblank.data, crtc);
-       }
-       spin_unlock_irqrestore(&disp->vblank.lock, flags);
-
-       if (disp->vblank.notify)
-               disp->vblank.notify(disp->vblank.data, crtc);
-}
-
 void
 nvd0_disp_intr(struct nouveau_subdev *subdev)
 {
@@ -920,7 +905,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
                if (mask & intr) {
                        u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
                        if (stat & 0x00000001)
-                               nvd0_disp_intr_vblank(priv, i);
+                               nouveau_event_trigger(priv->base.vblank, i);
                        nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
                        nv_rd32(priv, 0x6100c0 + (i * 0x800));
                }
@@ -933,10 +918,11 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_object **pobject)
 {
        struct nv50_disp_priv *priv;
+       int heads = nv_rd32(parent, 0x022448);
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
-                                 "display", &priv);
+       ret = nouveau_disp_create(parent, engine, oclass, heads,
+                                 "PDISP", "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
@@ -945,7 +931,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
        priv->sclass = nvd0_disp_sclass;
-       priv->head.nr = nv_rd32(priv, 0x022448);
+       priv->head.nr = heads;
        priv->dac.nr = 3;
        priv->sor.nr = 4;
        priv->dac.power = nv50_dac_power;
@@ -958,9 +944,6 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
        priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
        priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index 259537c4587e32a3f9b7a7e4e7b47d9d5b852612..5512296a61d7e7fe40ba426abcb16e2a524b6554 100644 (file)
@@ -51,10 +51,11 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_object **pobject)
 {
        struct nv50_disp_priv *priv;
+       int heads = nv_rd32(parent, 0x022448);
        int ret;
 
-       ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
-                                 "display", &priv);
+       ret = nouveau_disp_create(parent, engine, oclass, heads,
+                                 "PDISP", "display", &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
@@ -63,7 +64,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
        priv->sclass = nve0_disp_sclass;
-       priv->head.nr = nv_rd32(priv, 0x022448);
+       priv->head.nr = heads;
        priv->dac.nr = 3;
        priv->sor.nr = 4;
        priv->dac.power = nv50_dac_power;
@@ -76,9 +77,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
        priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
        priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
-
-       INIT_LIST_HEAD(&priv->base.vblank.list);
-       spin_lock_init(&priv->base.vblank.lock);
        return 0;
 }
 
index b0e7e1c01ce69b42d7c9150e2678858a07376663..c48e74953771a6c02352d43c0bfa59a84be13c0e 100644 (file)
@@ -28,6 +28,9 @@
 #include <core/namedb.h>
 #include <core/handle.h>
 #include <core/gpuobj.h>
+#include <core/event.h>
+
+#include <subdev/bar.h>
 
 #include <engine/software.h>
 #include <engine/disp.h>
@@ -90,18 +93,11 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
 {
        struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
        struct nouveau_disp *disp = nouveau_disp(object);
-       unsigned long flags;
        u32 crtc = *(u32 *)args;
-
        if (crtc > 1)
                return -EINVAL;
 
-       disp->vblank.get(disp->vblank.data, crtc);
-
-       spin_lock_irqsave(&disp->vblank.lock, flags);
-       list_add(&chan->base.vblank.head, &disp->vblank.list);
-       chan->base.vblank.crtc = crtc;
-       spin_unlock_irqrestore(&disp->vblank.lock, flags);
+       nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
        return 0;
 }
 
@@ -135,6 +131,29 @@ nv50_software_sclass[] = {
  * software context
  ******************************************************************************/
 
+static int
+nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
+{
+       struct nouveau_software_chan *chan =
+               container_of(event, struct nouveau_software_chan, vblank.event);
+       struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
+       struct nouveau_bar *bar = nouveau_bar(priv);
+
+       nv_wr32(priv, 0x001704, chan->vblank.channel);
+       nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
+       bar->flush(bar);
+
+       if (nv_device(priv)->chipset == 0x50) {
+               nv_wr32(priv, 0x001570, chan->vblank.offset);
+               nv_wr32(priv, 0x001574, chan->vblank.value);
+       } else {
+               nv_wr32(priv, 0x060010, chan->vblank.offset);
+               nv_wr32(priv, 0x060014, chan->vblank.value);
+       }
+
+       return NVKM_EVENT_DROP;
+}
+
 static int
 nv50_software_context_ctor(struct nouveau_object *parent,
                           struct nouveau_object *engine,
@@ -150,6 +169,7 @@ nv50_software_context_ctor(struct nouveau_object *parent,
                return ret;
 
        chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
+       chan->base.vblank.event.func = nv50_software_vblsem_release;
        return 0;
 }
 
@@ -170,8 +190,8 @@ nv50_software_cclass = {
 
 static int
 nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-             struct nouveau_oclass *oclass, void *data, u32 size,
-             struct nouveau_object **pobject)
+                  struct nouveau_oclass *oclass, void *data, u32 size,
+                  struct nouveau_object **pobject)
 {
        struct nv50_software_priv *priv;
        int ret;
index 282a1cd1bc2facbc887ffe721763e0e0e9df34a0..a523eaad47e3efb30206b953e2206828da97ea46 100644 (file)
@@ -25,6 +25,9 @@
 #include <core/os.h>
 #include <core/class.h>
 #include <core/engctx.h>
+#include <core/event.h>
+
+#include <subdev/bar.h>
 
 #include <engine/software.h>
 #include <engine/disp.h>
@@ -72,18 +75,12 @@ nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
 {
        struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
        struct nouveau_disp *disp = nouveau_disp(object);
-       unsigned long flags;
        u32 crtc = *(u32 *)args;
 
        if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
                return -EINVAL;
 
-       disp->vblank.get(disp->vblank.data, crtc);
-
-       spin_lock_irqsave(&disp->vblank.lock, flags);
-       list_add(&chan->base.vblank.head, &disp->vblank.list);
-       chan->base.vblank.crtc = crtc;
-       spin_unlock_irqrestore(&disp->vblank.lock, flags);
+       nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
        return 0;
 }
 
@@ -117,6 +114,23 @@ nvc0_software_sclass[] = {
  * software context
  ******************************************************************************/
 
+static int
+nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
+{
+       struct nouveau_software_chan *chan =
+               container_of(event, struct nouveau_software_chan, vblank.event);
+       struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
+       struct nouveau_bar *bar = nouveau_bar(priv);
+
+       nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
+       bar->flush(bar);
+       nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
+       nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
+       nv_wr32(priv, 0x060014, chan->vblank.value);
+
+       return NVKM_EVENT_DROP;
+}
+
 static int
 nvc0_software_context_ctor(struct nouveau_object *parent,
                           struct nouveau_object *engine,
@@ -132,6 +146,7 @@ nvc0_software_context_ctor(struct nouveau_object *parent,
                return ret;
 
        chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
+       chan->base.vblank.event.func = nvc0_software_vblsem_release;
        return 0;
 }
 
index 46948285f3e73d30b286905ad19ddea9ae36020e..28da6772c095560ec6ece447c971438ca37cb294 100644 (file)
@@ -4,18 +4,11 @@
 #include <core/object.h>
 #include <core/engine.h>
 #include <core/device.h>
+#include <core/event.h>
 
 struct nouveau_disp {
        struct nouveau_engine base;
-
-       struct {
-               struct list_head list;
-               spinlock_t lock;
-               void (*notify)(void *, int);
-               void (*get)(void *, int);
-               void (*put)(void *, int);
-               void *data;
-       } vblank;
+       struct nouveau_event *vblank;
 };
 
 static inline struct nouveau_disp *
@@ -24,16 +17,22 @@ nouveau_disp(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
 }
 
-#define nouveau_disp_create(p,e,c,i,x,d)                                       \
-       nouveau_engine_create((p), (e), (c), true, (i), (x), (d))
-#define nouveau_disp_destroy(d)                                                \
-       nouveau_engine_destroy(&(d)->base)
+#define nouveau_disp_create(p,e,c,h,i,x,d)                                     \
+       nouveau_disp_create_((p), (e), (c), (h), (i), (x),                     \
+                            sizeof(**d), (void **)d)
+#define nouveau_disp_destroy(d) ({                                             \
+       struct nouveau_disp *disp = (d);                                       \
+       _nouveau_disp_dtor(nv_object(disp));                                   \
+})
 #define nouveau_disp_init(d)                                                   \
        nouveau_engine_init(&(d)->base)
 #define nouveau_disp_fini(d,s)                                                 \
        nouveau_engine_fini(&(d)->base, (s))
 
-#define _nouveau_disp_dtor _nouveau_engine_dtor
+int  nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
+                         struct nouveau_oclass *, int heads,
+                         const char *, const char *, int, void **);
+void _nouveau_disp_dtor(struct nouveau_object *);
 #define _nouveau_disp_init _nouveau_engine_init
 #define _nouveau_disp_fini _nouveau_engine_fini
 
index c945691c8564d0d0f05b13f16524c877ccdb1e91..45799487e573e226856247d21087f18ccfbf09c6 100644 (file)
@@ -3,17 +3,17 @@
 
 #include <core/engine.h>
 #include <core/engctx.h>
+#include <core/event.h>
 
 struct nouveau_software_chan {
        struct nouveau_engctx base;
 
        struct {
-               struct list_head head;
+               struct nouveau_eventh event;
                u32 channel;
                u32 ctxdma;
                u64 offset;
                u32 value;
-               u32 crtc;
        } vblank;
 
        int (*flip)(void *);
index e2fdd7552e1bbdacf2dc41c5270ce1786441b2f1..9f84803b1fb36df2f76bec8cd017b1eac39d2d56 100644 (file)
@@ -41,6 +41,8 @@
 #include <subdev/gpio.h>
 #include <engine/disp.h>
 
+#include <core/class.h>
+
 static void
 nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
 {
@@ -257,29 +259,10 @@ nouveau_display_fini(struct drm_device *dev)
        disp->fini(dev);
 }
 
-static void
-nouveau_display_vblank_notify(void *data, int crtc)
-{
-       drm_handle_vblank(data, crtc);
-}
-
-static void
-nouveau_display_vblank_get(void *data, int crtc)
-{
-       drm_vblank_get(data, crtc);
-}
-
-static void
-nouveau_display_vblank_put(void *data, int crtc)
-{
-       drm_vblank_put(data, crtc);
-}
-
 int
 nouveau_display_create(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
        struct nouveau_display *disp;
        u32 pclass = dev->pdev->class >> 8;
        int ret, gen;
@@ -288,11 +271,6 @@ nouveau_display_create(struct drm_device *dev)
        if (!disp)
                return -ENOMEM;
 
-       pdisp->vblank.data = dev;
-       pdisp->vblank.notify = nouveau_display_vblank_notify;
-       pdisp->vblank.get = nouveau_display_vblank_get;
-       pdisp->vblank.put = nouveau_display_vblank_put;
-
        drm_mode_config_init(dev);
        drm_mode_create_scaling_mode_property(dev);
        drm_mode_create_dvi_i_properties(dev);
@@ -474,39 +452,6 @@ nouveau_display_resume(struct drm_device *dev)
        }
 }
 
-int
-nouveau_vblank_enable(struct drm_device *dev, int crtc)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-
-       if (device->card_type >= NV_D0)
-               nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 1);
-       else
-       if (device->card_type >= NV_50)
-               nv_mask(device, 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 nouveau_device *device = nouveau_dev(dev);
-
-       if (device->card_type >= NV_D0)
-               nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 0);
-       else
-       if (device->card_type >= NV_50)
-               nv_mask(device, NV50_PDISPLAY_INTR_EN_1,
-                       NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
-       else
-               NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
-}
-
 static int
 nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
                          struct nouveau_bo *new_bo)
index 722548bb3bd3c23da77d1d2e25aeb36817a816d2..1ea3e4734b621f6e103a034f69696ea9b35529df 100644 (file)
@@ -59,9 +59,6 @@ void nouveau_display_fini(struct drm_device *dev);
 int  nouveau_display_suspend(struct drm_device *dev);
 void nouveau_display_resume(struct drm_device *dev);
 
-int  nouveau_vblank_enable(struct drm_device *dev, int crtc);
-void nouveau_vblank_disable(struct drm_device *dev, int crtc);
-
 int  nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                            struct drm_pending_vblank_event *event);
 int  nouveau_finish_page_flip(struct nouveau_channel *,
index ef1ad21fd37ff3e0a0980b9ba23584470882ac75..ce91c8d43bb718e9d837a4fd0a58c5bf0b62adbc 100644 (file)
@@ -34,6 +34,8 @@
 #include <subdev/device.h>
 #include <subdev/vm.h>
 
+#include <engine/disp.h>
+
 #include "nouveau_drm.h"
 #include "nouveau_irq.h"
 #include "nouveau_dma.h"
@@ -68,6 +70,32 @@ module_param_named(modeset, nouveau_modeset, int, 0400);
 
 static struct drm_driver driver;
 
+static int
+nouveau_drm_vblank_enable(struct drm_device *dev, int head)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
+       nouveau_event_get(pdisp->vblank, head, &drm->vblank);
+       return 0;
+}
+
+static void
+nouveau_drm_vblank_disable(struct drm_device *dev, int head)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
+       nouveau_event_put(pdisp->vblank, head, &drm->vblank);
+}
+
+static int
+nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
+{
+       struct nouveau_drm *drm =
+               container_of(event, struct nouveau_drm, vblank);
+       drm_handle_vblank(drm->dev, head);
+       return NVKM_EVENT_KEEP;
+}
+
 static u64
 nouveau_name(struct pci_dev *pdev)
 {
@@ -259,6 +287,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 
        dev->dev_private = drm;
        drm->dev = dev;
+       drm->vblank.func = nouveau_drm_vblank_handler;
 
        INIT_LIST_HEAD(&drm->clients);
        spin_lock_init(&drm->tile.lock);
@@ -643,8 +672,8 @@ driver = {
        .irq_handler = nouveau_irq_handler,
 
        .get_vblank_counter = drm_vblank_count,
-       .enable_vblank = nouveau_vblank_enable,
-       .disable_vblank = nouveau_vblank_disable,
+       .enable_vblank = nouveau_drm_vblank_enable,
+       .disable_vblank = nouveau_drm_vblank_disable,
 
        .ioctls = nouveau_ioctls,
        .fops = &nouveau_driver_fops,
index aa89eb938b47441049034117790ec614cc771fbc..b25df374c901df36f1c6e9408225ef9a2ed4b813 100644 (file)
@@ -13,6 +13,7 @@
 #define DRIVER_PATCHLEVEL      0
 
 #include <core/client.h>
+#include <core/event.h>
 
 #include <subdev/vm.h>
 
@@ -112,6 +113,7 @@ struct nouveau_drm {
        struct nvbios vbios;
        struct nouveau_display *display;
        struct backlight_device *backlight;
+       struct nouveau_eventh vblank;
 
        /* power management */
        struct nouveau_pm *pm;