aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-01-30 18:23:34 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-02-20 01:00:46 -0500
commit1d7c71a3e2f77336df536855b0efd2dc5bdeb41b (patch)
tree8343ee580c5de2abcab27bc1bf51a7f44563e4d2 /drivers/gpu/drm/nouveau
parent21a5ace0bfb737d65e6d345ccf3d63fdee141f98 (diff)
drm/nouveau/disp: port vblank handling to event interface
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>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/base.c52
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv04.c31
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c70
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv84.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv94.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva0.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva3.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c59
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nve0.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv50.c40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nvc0.c29
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/disp.h27
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/software.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c59
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c33
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h2
19 files changed, 226 insertions, 216 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 6d4cb8aec4de..ebe37fe5d0fc 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -143,6 +143,7 @@ nouveau-y += core/engine/copy/nvc0.o
143nouveau-y += core/engine/copy/nve0.o 143nouveau-y += core/engine/copy/nve0.o
144nouveau-y += core/engine/crypt/nv84.o 144nouveau-y += core/engine/crypt/nv84.o
145nouveau-y += core/engine/crypt/nv98.o 145nouveau-y += core/engine/crypt/nv98.o
146nouveau-y += core/engine/disp/base.o
146nouveau-y += core/engine/disp/nv04.o 147nouveau-y += core/engine/disp/nv04.o
147nouveau-y += core/engine/disp/nv50.o 148nouveau-y += core/engine/disp/nv50.o
148nouveau-y += core/engine/disp/nv84.o 149nouveau-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
index 000000000000..7a5cae42834f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
@@ -0,0 +1,52 @@
1/*
2 * Copyright 2013 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include <engine/disp.h>
26
27void
28_nouveau_disp_dtor(struct nouveau_object *object)
29{
30 struct nouveau_disp *disp = (void *)object;
31 nouveau_event_destroy(&disp->vblank);
32 nouveau_engine_destroy(&disp->base);
33}
34
35int
36nouveau_disp_create_(struct nouveau_object *parent,
37 struct nouveau_object *engine,
38 struct nouveau_oclass *oclass, int heads,
39 const char *intname, const char *extname,
40 int length, void **pobject)
41{
42 struct nouveau_disp *disp;
43 int ret;
44
45 ret = nouveau_engine_create_(parent, engine, oclass, true,
46 intname, extname, length, pobject);
47 disp = *pobject;
48 if (ret)
49 return ret;
50
51 return nouveau_event_create(heads, &disp->vblank);
52}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
index 6eaf7257be77..05e903f08a36 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
@@ -23,6 +23,8 @@
23 */ 23 */
24 24
25#include <engine/disp.h> 25#include <engine/disp.h>
26
27#include <core/event.h>
26#include <core/class.h> 28#include <core/class.h>
27 29
28struct nv04_disp_priv { 30struct nv04_disp_priv {
@@ -35,12 +37,20 @@ nv04_disp_sclass[] = {
35 {}, 37 {},
36}; 38};
37 39
40/*******************************************************************************
41 * Display engine implementation
42 ******************************************************************************/
43
44static void
45nv04_disp_vblank_enable(struct nouveau_event *event, int head)
46{
47 nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
48}
49
38static void 50static void
39nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc) 51nv04_disp_vblank_disable(struct nouveau_event *event, int head)
40{ 52{
41 struct nouveau_disp *disp = &priv->base; 53 nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
42 if (disp->vblank.notify)
43 disp->vblank.notify(disp->vblank.data, crtc);
44} 54}
45 55
46static void 56static void
@@ -51,25 +61,25 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
51 u32 crtc1 = nv_rd32(priv, 0x602100); 61 u32 crtc1 = nv_rd32(priv, 0x602100);
52 62
53 if (crtc0 & 0x00000001) { 63 if (crtc0 & 0x00000001) {
54 nv04_disp_intr_vblank(priv, 0); 64 nouveau_event_trigger(priv->base.vblank, 0);
55 nv_wr32(priv, 0x600100, 0x00000001); 65 nv_wr32(priv, 0x600100, 0x00000001);
56 } 66 }
57 67
58 if (crtc1 & 0x00000001) { 68 if (crtc1 & 0x00000001) {
59 nv04_disp_intr_vblank(priv, 1); 69 nouveau_event_trigger(priv->base.vblank, 1);
60 nv_wr32(priv, 0x602100, 0x00000001); 70 nv_wr32(priv, 0x602100, 0x00000001);
61 } 71 }
62} 72}
63 73
64static int 74static int
65nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 75nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
66 struct nouveau_oclass *oclass, void *data, u32 size, 76 struct nouveau_oclass *oclass, void *data, u32 size,
67 struct nouveau_object **pobject) 77 struct nouveau_object **pobject)
68{ 78{
69 struct nv04_disp_priv *priv; 79 struct nv04_disp_priv *priv;
70 int ret; 80 int ret;
71 81
72 ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY", 82 ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
73 "display", &priv); 83 "display", &priv);
74 *pobject = nv_object(priv); 84 *pobject = nv_object(priv);
75 if (ret) 85 if (ret)
@@ -77,6 +87,9 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
77 87
78 nv_engine(priv)->sclass = nv04_disp_sclass; 88 nv_engine(priv)->sclass = nv04_disp_sclass;
79 nv_subdev(priv)->intr = nv04_disp_intr; 89 nv_subdev(priv)->intr = nv04_disp_intr;
90 priv->base.vblank->priv = priv;
91 priv->base.vblank->enable = nv04_disp_vblank_enable;
92 priv->base.vblank->disable = nv04_disp_vblank_disable;
80 return 0; 93 return 0;
81} 94}
82 95
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index ca1a7d76a95b..0d26f00a2f15 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -27,7 +27,6 @@
27#include <core/handle.h> 27#include <core/handle.h>
28#include <core/class.h> 28#include <core/class.h>
29 29
30#include <engine/software.h>
31#include <engine/disp.h> 30#include <engine/disp.h>
32 31
33#include <subdev/bios.h> 32#include <subdev/bios.h>
@@ -37,7 +36,6 @@
37#include <subdev/bios/pll.h> 36#include <subdev/bios/pll.h>
38#include <subdev/timer.h> 37#include <subdev/timer.h>
39#include <subdev/fb.h> 38#include <subdev/fb.h>
40#include <subdev/bar.h>
41#include <subdev/clock.h> 39#include <subdev/clock.h>
42 40
43#include "nv50.h" 41#include "nv50.h"
@@ -543,6 +541,18 @@ nv50_disp_curs_ofuncs = {
543 * Base display object 541 * Base display object
544 ******************************************************************************/ 542 ******************************************************************************/
545 543
544static void
545nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
546{
547 nv_mask(event->priv, 0x61002c, (1 << head), (1 << head));
548}
549
550static void
551nv50_disp_base_vblank_disable(struct nouveau_event *event, int head)
552{
553 nv_mask(event->priv, 0x61002c, (1 << head), (0 << head));
554}
555
546static int 556static int
547nv50_disp_base_ctor(struct nouveau_object *parent, 557nv50_disp_base_ctor(struct nouveau_object *parent,
548 struct nouveau_object *engine, 558 struct nouveau_object *engine,
@@ -559,6 +569,9 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
559 if (ret) 569 if (ret)
560 return ret; 570 return ret;
561 571
572 priv->base.vblank->priv = priv;
573 priv->base.vblank->enable = nv50_disp_base_vblank_enable;
574 priv->base.vblank->disable = nv50_disp_base_vblank_disable;
562 return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); 575 return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
563} 576}
564 577
@@ -756,50 +769,6 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv)
756 } 769 }
757} 770}
758 771
759static void
760nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
761{
762 struct nouveau_bar *bar = nouveau_bar(priv);
763 struct nouveau_disp *disp = &priv->base;
764 struct nouveau_software_chan *chan, *temp;
765 unsigned long flags;
766
767 spin_lock_irqsave(&disp->vblank.lock, flags);
768 list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
769 if (chan->vblank.crtc != crtc)
770 continue;
771
772 if (nv_device(priv)->chipset >= 0xc0) {
773 nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
774 bar->flush(bar);
775 nv_wr32(priv, 0x06000c,
776 upper_32_bits(chan->vblank.offset));
777 nv_wr32(priv, 0x060010,
778 lower_32_bits(chan->vblank.offset));
779 nv_wr32(priv, 0x060014, chan->vblank.value);
780 } else {
781 nv_wr32(priv, 0x001704, chan->vblank.channel);
782 nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
783 bar->flush(bar);
784 if (nv_device(priv)->chipset == 0x50) {
785 nv_wr32(priv, 0x001570, chan->vblank.offset);
786 nv_wr32(priv, 0x001574, chan->vblank.value);
787 } else {
788 nv_wr32(priv, 0x060010, chan->vblank.offset);
789 nv_wr32(priv, 0x060014, chan->vblank.value);
790 }
791 }
792
793 list_del(&chan->vblank.head);
794 if (disp->vblank.put)
795 disp->vblank.put(disp->vblank.data, crtc);
796 }
797 spin_unlock_irqrestore(&disp->vblank.lock, flags);
798
799 if (disp->vblank.notify)
800 disp->vblank.notify(disp->vblank.data, crtc);
801}
802
803static u16 772static u16
804exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, 773exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
805 struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 774 struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
@@ -1201,13 +1170,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
1201 } 1170 }
1202 1171
1203 if (intr1 & 0x00000004) { 1172 if (intr1 & 0x00000004) {
1204 nv50_disp_intr_vblank(priv, 0); 1173 nouveau_event_trigger(priv->base.vblank, 0);
1205 nv_wr32(priv, 0x610024, 0x00000004); 1174 nv_wr32(priv, 0x610024, 0x00000004);
1206 intr1 &= ~0x00000004; 1175 intr1 &= ~0x00000004;
1207 } 1176 }
1208 1177
1209 if (intr1 & 0x00000008) { 1178 if (intr1 & 0x00000008) {
1210 nv50_disp_intr_vblank(priv, 1); 1179 nouveau_event_trigger(priv->base.vblank, 1);
1211 nv_wr32(priv, 0x610024, 0x00000008); 1180 nv_wr32(priv, 0x610024, 0x00000008);
1212 intr1 &= ~0x00000008; 1181 intr1 &= ~0x00000008;
1213 } 1182 }
@@ -1226,7 +1195,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1226 struct nv50_disp_priv *priv; 1195 struct nv50_disp_priv *priv;
1227 int ret; 1196 int ret;
1228 1197
1229 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 1198 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
1230 "display", &priv); 1199 "display", &priv);
1231 *pobject = nv_object(priv); 1200 *pobject = nv_object(priv);
1232 if (ret) 1201 if (ret)
@@ -1242,9 +1211,6 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1242 priv->dac.power = nv50_dac_power; 1211 priv->dac.power = nv50_dac_power;
1243 priv->dac.sense = nv50_dac_sense; 1212 priv->dac.sense = nv50_dac_sense;
1244 priv->sor.power = nv50_sor_power; 1213 priv->sor.power = nv50_sor_power;
1245
1246 INIT_LIST_HEAD(&priv->base.vblank.list);
1247 spin_lock_init(&priv->base.vblank.lock);
1248 return 0; 1214 return 0;
1249} 1215}
1250 1216
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
index a6bb931450f1..fc897181fa38 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
@@ -3,7 +3,9 @@
3 3
4#include <core/parent.h> 4#include <core/parent.h>
5#include <core/namedb.h> 5#include <core/namedb.h>
6#include <core/engctx.h>
6#include <core/ramht.h> 7#include <core/ramht.h>
8#include <core/event.h>
7 9
8#include <engine/dmaobj.h> 10#include <engine/dmaobj.h>
9#include <engine/disp.h> 11#include <engine/disp.h>
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
index fc84eacdfbec..a2153424605d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
@@ -63,7 +63,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
63 struct nv50_disp_priv *priv; 63 struct nv50_disp_priv *priv;
64 int ret; 64 int ret;
65 65
66 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 66 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
67 "display", &priv); 67 "display", &priv);
68 *pobject = nv_object(priv); 68 *pobject = nv_object(priv);
69 if (ret) 69 if (ret)
@@ -80,9 +80,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
80 priv->dac.sense = nv50_dac_sense; 80 priv->dac.sense = nv50_dac_sense;
81 priv->sor.power = nv50_sor_power; 81 priv->sor.power = nv50_sor_power;
82 priv->sor.hdmi = nv84_hdmi_ctrl; 82 priv->sor.hdmi = nv84_hdmi_ctrl;
83
84 INIT_LIST_HEAD(&priv->base.vblank.list);
85 spin_lock_init(&priv->base.vblank.lock);
86 return 0; 83 return 0;
87} 84}
88 85
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
index ba9dfd4669a2..a315e28ac17e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
@@ -69,7 +69,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
69 struct nv50_disp_priv *priv; 69 struct nv50_disp_priv *priv;
70 int ret; 70 int ret;
71 71
72 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 72 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
73 "display", &priv); 73 "display", &priv);
74 *pobject = nv_object(priv); 74 *pobject = nv_object(priv);
75 if (ret) 75 if (ret)
@@ -91,9 +91,6 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
91 priv->sor.dp_train_fini = nv94_sor_dp_train_fini; 91 priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
92 priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl; 92 priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
93 priv->sor.dp_drvctl = nv94_sor_dp_drvctl; 93 priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
94
95 INIT_LIST_HEAD(&priv->base.vblank.list);
96 spin_lock_init(&priv->base.vblank.lock);
97 return 0; 94 return 0;
98} 95}
99 96
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
index 5d63902cdeda..480e2ded95fa 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
@@ -53,7 +53,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
53 struct nv50_disp_priv *priv; 53 struct nv50_disp_priv *priv;
54 int ret; 54 int ret;
55 55
56 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 56 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
57 "display", &priv); 57 "display", &priv);
58 *pobject = nv_object(priv); 58 *pobject = nv_object(priv);
59 if (ret) 59 if (ret)
@@ -70,9 +70,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
70 priv->dac.sense = nv50_dac_sense; 70 priv->dac.sense = nv50_dac_sense;
71 priv->sor.power = nv50_sor_power; 71 priv->sor.power = nv50_sor_power;
72 priv->sor.hdmi = nv84_hdmi_ctrl; 72 priv->sor.hdmi = nv84_hdmi_ctrl;
73
74 INIT_LIST_HEAD(&priv->base.vblank.list);
75 spin_lock_init(&priv->base.vblank.lock);
76 return 0; 73 return 0;
77} 74}
78 75
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
index e9192ca389fa..718b4f66352e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
@@ -70,7 +70,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
70 struct nv50_disp_priv *priv; 70 struct nv50_disp_priv *priv;
71 int ret; 71 int ret;
72 72
73 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 73 ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
74 "display", &priv); 74 "display", &priv);
75 *pobject = nv_object(priv); 75 *pobject = nv_object(priv);
76 if (ret) 76 if (ret)
@@ -93,9 +93,6 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
93 priv->sor.dp_train_fini = nv94_sor_dp_train_fini; 93 priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
94 priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl; 94 priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
95 priv->sor.dp_drvctl = nv94_sor_dp_drvctl; 95 priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
96
97 INIT_LIST_HEAD(&priv->base.vblank.list);
98 spin_lock_init(&priv->base.vblank.lock);
99 return 0; 96 return 0;
100} 97}
101 98
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 9e38ebff5fb3..74626e8c020b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -27,12 +27,10 @@
27#include <core/handle.h> 27#include <core/handle.h>
28#include <core/class.h> 28#include <core/class.h>
29 29
30#include <engine/software.h>
31#include <engine/disp.h> 30#include <engine/disp.h>
32 31
33#include <subdev/timer.h> 32#include <subdev/timer.h>
34#include <subdev/fb.h> 33#include <subdev/fb.h>
35#include <subdev/bar.h>
36#include <subdev/clock.h> 34#include <subdev/clock.h>
37 35
38#include <subdev/bios.h> 36#include <subdev/bios.h>
@@ -443,6 +441,18 @@ nvd0_disp_curs_ofuncs = {
443 * Base display object 441 * Base display object
444 ******************************************************************************/ 442 ******************************************************************************/
445 443
444static void
445nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
446{
447 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
448}
449
450static void
451nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head)
452{
453 nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
454}
455
446static int 456static int
447nvd0_disp_base_ctor(struct nouveau_object *parent, 457nvd0_disp_base_ctor(struct nouveau_object *parent,
448 struct nouveau_object *engine, 458 struct nouveau_object *engine,
@@ -459,6 +469,10 @@ nvd0_disp_base_ctor(struct nouveau_object *parent,
459 if (ret) 469 if (ret)
460 return ret; 470 return ret;
461 471
472 priv->base.vblank->priv = priv;
473 priv->base.vblank->enable = nvd0_disp_base_vblank_enable;
474 priv->base.vblank->disable = nvd0_disp_base_vblank_disable;
475
462 return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); 476 return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
463} 477}
464 478
@@ -822,35 +836,6 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
822 nv_wr32(priv, 0x6101d0, 0x80000000); 836 nv_wr32(priv, 0x6101d0, 0x80000000);
823} 837}
824 838
825static void
826nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
827{
828 struct nouveau_bar *bar = nouveau_bar(priv);
829 struct nouveau_disp *disp = &priv->base;
830 struct nouveau_software_chan *chan, *temp;
831 unsigned long flags;
832
833 spin_lock_irqsave(&disp->vblank.lock, flags);
834 list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
835 if (chan->vblank.crtc != crtc)
836 continue;
837
838 nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
839 bar->flush(bar);
840 nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
841 nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
842 nv_wr32(priv, 0x060014, chan->vblank.value);
843
844 list_del(&chan->vblank.head);
845 if (disp->vblank.put)
846 disp->vblank.put(disp->vblank.data, crtc);
847 }
848 spin_unlock_irqrestore(&disp->vblank.lock, flags);
849
850 if (disp->vblank.notify)
851 disp->vblank.notify(disp->vblank.data, crtc);
852}
853
854void 839void
855nvd0_disp_intr(struct nouveau_subdev *subdev) 840nvd0_disp_intr(struct nouveau_subdev *subdev)
856{ 841{
@@ -920,7 +905,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
920 if (mask & intr) { 905 if (mask & intr) {
921 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); 906 u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
922 if (stat & 0x00000001) 907 if (stat & 0x00000001)
923 nvd0_disp_intr_vblank(priv, i); 908 nouveau_event_trigger(priv->base.vblank, i);
924 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); 909 nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
925 nv_rd32(priv, 0x6100c0 + (i * 0x800)); 910 nv_rd32(priv, 0x6100c0 + (i * 0x800));
926 } 911 }
@@ -933,10 +918,11 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
933 struct nouveau_object **pobject) 918 struct nouveau_object **pobject)
934{ 919{
935 struct nv50_disp_priv *priv; 920 struct nv50_disp_priv *priv;
921 int heads = nv_rd32(parent, 0x022448);
936 int ret; 922 int ret;
937 923
938 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 924 ret = nouveau_disp_create(parent, engine, oclass, heads,
939 "display", &priv); 925 "PDISP", "display", &priv);
940 *pobject = nv_object(priv); 926 *pobject = nv_object(priv);
941 if (ret) 927 if (ret)
942 return ret; 928 return ret;
@@ -945,7 +931,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
945 nv_engine(priv)->cclass = &nv50_disp_cclass; 931 nv_engine(priv)->cclass = &nv50_disp_cclass;
946 nv_subdev(priv)->intr = nvd0_disp_intr; 932 nv_subdev(priv)->intr = nvd0_disp_intr;
947 priv->sclass = nvd0_disp_sclass; 933 priv->sclass = nvd0_disp_sclass;
948 priv->head.nr = nv_rd32(priv, 0x022448); 934 priv->head.nr = heads;
949 priv->dac.nr = 3; 935 priv->dac.nr = 3;
950 priv->sor.nr = 4; 936 priv->sor.nr = 4;
951 priv->dac.power = nv50_dac_power; 937 priv->dac.power = nv50_dac_power;
@@ -958,9 +944,6 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
958 priv->sor.dp_train_fini = nv94_sor_dp_train_fini; 944 priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
959 priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; 945 priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
960 priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; 946 priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
961
962 INIT_LIST_HEAD(&priv->base.vblank.list);
963 spin_lock_init(&priv->base.vblank.lock);
964 return 0; 947 return 0;
965} 948}
966 949
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index 259537c4587e..5512296a61d7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -51,10 +51,11 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
51 struct nouveau_object **pobject) 51 struct nouveau_object **pobject)
52{ 52{
53 struct nv50_disp_priv *priv; 53 struct nv50_disp_priv *priv;
54 int heads = nv_rd32(parent, 0x022448);
54 int ret; 55 int ret;
55 56
56 ret = nouveau_disp_create(parent, engine, oclass, "PDISP", 57 ret = nouveau_disp_create(parent, engine, oclass, heads,
57 "display", &priv); 58 "PDISP", "display", &priv);
58 *pobject = nv_object(priv); 59 *pobject = nv_object(priv);
59 if (ret) 60 if (ret)
60 return ret; 61 return ret;
@@ -63,7 +64,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
63 nv_engine(priv)->cclass = &nv50_disp_cclass; 64 nv_engine(priv)->cclass = &nv50_disp_cclass;
64 nv_subdev(priv)->intr = nvd0_disp_intr; 65 nv_subdev(priv)->intr = nvd0_disp_intr;
65 priv->sclass = nve0_disp_sclass; 66 priv->sclass = nve0_disp_sclass;
66 priv->head.nr = nv_rd32(priv, 0x022448); 67 priv->head.nr = heads;
67 priv->dac.nr = 3; 68 priv->dac.nr = 3;
68 priv->sor.nr = 4; 69 priv->sor.nr = 4;
69 priv->dac.power = nv50_dac_power; 70 priv->dac.power = nv50_dac_power;
@@ -76,9 +77,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
76 priv->sor.dp_train_fini = nv94_sor_dp_train_fini; 77 priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
77 priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; 78 priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
78 priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; 79 priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
79
80 INIT_LIST_HEAD(&priv->base.vblank.list);
81 spin_lock_init(&priv->base.vblank.lock);
82 return 0; 80 return 0;
83} 81}
84 82
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
index b0e7e1c01ce6..c48e74953771 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
@@ -28,6 +28,9 @@
28#include <core/namedb.h> 28#include <core/namedb.h>
29#include <core/handle.h> 29#include <core/handle.h>
30#include <core/gpuobj.h> 30#include <core/gpuobj.h>
31#include <core/event.h>
32
33#include <subdev/bar.h>
31 34
32#include <engine/software.h> 35#include <engine/software.h>
33#include <engine/disp.h> 36#include <engine/disp.h>
@@ -90,18 +93,11 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
90{ 93{
91 struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); 94 struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
92 struct nouveau_disp *disp = nouveau_disp(object); 95 struct nouveau_disp *disp = nouveau_disp(object);
93 unsigned long flags;
94 u32 crtc = *(u32 *)args; 96 u32 crtc = *(u32 *)args;
95
96 if (crtc > 1) 97 if (crtc > 1)
97 return -EINVAL; 98 return -EINVAL;
98 99
99 disp->vblank.get(disp->vblank.data, crtc); 100 nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
100
101 spin_lock_irqsave(&disp->vblank.lock, flags);
102 list_add(&chan->base.vblank.head, &disp->vblank.list);
103 chan->base.vblank.crtc = crtc;
104 spin_unlock_irqrestore(&disp->vblank.lock, flags);
105 return 0; 101 return 0;
106} 102}
107 103
@@ -136,6 +132,29 @@ nv50_software_sclass[] = {
136 ******************************************************************************/ 132 ******************************************************************************/
137 133
138static int 134static int
135nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
136{
137 struct nouveau_software_chan *chan =
138 container_of(event, struct nouveau_software_chan, vblank.event);
139 struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
140 struct nouveau_bar *bar = nouveau_bar(priv);
141
142 nv_wr32(priv, 0x001704, chan->vblank.channel);
143 nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
144 bar->flush(bar);
145
146 if (nv_device(priv)->chipset == 0x50) {
147 nv_wr32(priv, 0x001570, chan->vblank.offset);
148 nv_wr32(priv, 0x001574, chan->vblank.value);
149 } else {
150 nv_wr32(priv, 0x060010, chan->vblank.offset);
151 nv_wr32(priv, 0x060014, chan->vblank.value);
152 }
153
154 return NVKM_EVENT_DROP;
155}
156
157static int
139nv50_software_context_ctor(struct nouveau_object *parent, 158nv50_software_context_ctor(struct nouveau_object *parent,
140 struct nouveau_object *engine, 159 struct nouveau_object *engine,
141 struct nouveau_oclass *oclass, void *data, u32 size, 160 struct nouveau_oclass *oclass, void *data, u32 size,
@@ -150,6 +169,7 @@ nv50_software_context_ctor(struct nouveau_object *parent,
150 return ret; 169 return ret;
151 170
152 chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; 171 chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
172 chan->base.vblank.event.func = nv50_software_vblsem_release;
153 return 0; 173 return 0;
154} 174}
155 175
@@ -170,8 +190,8 @@ nv50_software_cclass = {
170 190
171static int 191static int
172nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 192nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
173 struct nouveau_oclass *oclass, void *data, u32 size, 193 struct nouveau_oclass *oclass, void *data, u32 size,
174 struct nouveau_object **pobject) 194 struct nouveau_object **pobject)
175{ 195{
176 struct nv50_software_priv *priv; 196 struct nv50_software_priv *priv;
177 int ret; 197 int ret;
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
index 282a1cd1bc2f..a523eaad47e3 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
@@ -25,6 +25,9 @@
25#include <core/os.h> 25#include <core/os.h>
26#include <core/class.h> 26#include <core/class.h>
27#include <core/engctx.h> 27#include <core/engctx.h>
28#include <core/event.h>
29
30#include <subdev/bar.h>
28 31
29#include <engine/software.h> 32#include <engine/software.h>
30#include <engine/disp.h> 33#include <engine/disp.h>
@@ -72,18 +75,12 @@ nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
72{ 75{
73 struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); 76 struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
74 struct nouveau_disp *disp = nouveau_disp(object); 77 struct nouveau_disp *disp = nouveau_disp(object);
75 unsigned long flags;
76 u32 crtc = *(u32 *)args; 78 u32 crtc = *(u32 *)args;
77 79
78 if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3) 80 if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
79 return -EINVAL; 81 return -EINVAL;
80 82
81 disp->vblank.get(disp->vblank.data, crtc); 83 nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
82
83 spin_lock_irqsave(&disp->vblank.lock, flags);
84 list_add(&chan->base.vblank.head, &disp->vblank.list);
85 chan->base.vblank.crtc = crtc;
86 spin_unlock_irqrestore(&disp->vblank.lock, flags);
87 return 0; 84 return 0;
88} 85}
89 86
@@ -118,6 +115,23 @@ nvc0_software_sclass[] = {
118 ******************************************************************************/ 115 ******************************************************************************/
119 116
120static int 117static int
118nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
119{
120 struct nouveau_software_chan *chan =
121 container_of(event, struct nouveau_software_chan, vblank.event);
122 struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
123 struct nouveau_bar *bar = nouveau_bar(priv);
124
125 nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
126 bar->flush(bar);
127 nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
128 nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
129 nv_wr32(priv, 0x060014, chan->vblank.value);
130
131 return NVKM_EVENT_DROP;
132}
133
134static int
121nvc0_software_context_ctor(struct nouveau_object *parent, 135nvc0_software_context_ctor(struct nouveau_object *parent,
122 struct nouveau_object *engine, 136 struct nouveau_object *engine,
123 struct nouveau_oclass *oclass, void *data, u32 size, 137 struct nouveau_oclass *oclass, void *data, u32 size,
@@ -132,6 +146,7 @@ nvc0_software_context_ctor(struct nouveau_object *parent,
132 return ret; 146 return ret;
133 147
134 chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; 148 chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
149 chan->base.vblank.event.func = nvc0_software_vblsem_release;
135 return 0; 150 return 0;
136} 151}
137 152
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
index 46948285f3e7..28da6772c095 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
@@ -4,18 +4,11 @@
4#include <core/object.h> 4#include <core/object.h>
5#include <core/engine.h> 5#include <core/engine.h>
6#include <core/device.h> 6#include <core/device.h>
7#include <core/event.h>
7 8
8struct nouveau_disp { 9struct nouveau_disp {
9 struct nouveau_engine base; 10 struct nouveau_engine base;
10 11 struct nouveau_event *vblank;
11 struct {
12 struct list_head list;
13 spinlock_t lock;
14 void (*notify)(void *, int);
15 void (*get)(void *, int);
16 void (*put)(void *, int);
17 void *data;
18 } vblank;
19}; 12};
20 13
21static inline struct nouveau_disp * 14static inline struct nouveau_disp *
@@ -24,16 +17,22 @@ nouveau_disp(void *obj)
24 return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; 17 return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
25} 18}
26 19
27#define nouveau_disp_create(p,e,c,i,x,d) \ 20#define nouveau_disp_create(p,e,c,h,i,x,d) \
28 nouveau_engine_create((p), (e), (c), true, (i), (x), (d)) 21 nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
29#define nouveau_disp_destroy(d) \ 22 sizeof(**d), (void **)d)
30 nouveau_engine_destroy(&(d)->base) 23#define nouveau_disp_destroy(d) ({ \
24 struct nouveau_disp *disp = (d); \
25 _nouveau_disp_dtor(nv_object(disp)); \
26})
31#define nouveau_disp_init(d) \ 27#define nouveau_disp_init(d) \
32 nouveau_engine_init(&(d)->base) 28 nouveau_engine_init(&(d)->base)
33#define nouveau_disp_fini(d,s) \ 29#define nouveau_disp_fini(d,s) \
34 nouveau_engine_fini(&(d)->base, (s)) 30 nouveau_engine_fini(&(d)->base, (s))
35 31
36#define _nouveau_disp_dtor _nouveau_engine_dtor 32int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
33 struct nouveau_oclass *, int heads,
34 const char *, const char *, int, void **);
35void _nouveau_disp_dtor(struct nouveau_object *);
37#define _nouveau_disp_init _nouveau_engine_init 36#define _nouveau_disp_init _nouveau_engine_init
38#define _nouveau_disp_fini _nouveau_engine_fini 37#define _nouveau_disp_fini _nouveau_engine_fini
39 38
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h
index c945691c8564..45799487e573 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/software.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/software.h
@@ -3,17 +3,17 @@
3 3
4#include <core/engine.h> 4#include <core/engine.h>
5#include <core/engctx.h> 5#include <core/engctx.h>
6#include <core/event.h>
6 7
7struct nouveau_software_chan { 8struct nouveau_software_chan {
8 struct nouveau_engctx base; 9 struct nouveau_engctx base;
9 10
10 struct { 11 struct {
11 struct list_head head; 12 struct nouveau_eventh event;
12 u32 channel; 13 u32 channel;
13 u32 ctxdma; 14 u32 ctxdma;
14 u64 offset; 15 u64 offset;
15 u32 value; 16 u32 value;
16 u32 crtc;
17 } vblank; 17 } vblank;
18 18
19 int (*flip)(void *); 19 int (*flip)(void *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index e2fdd7552e1b..9f84803b1fb3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -41,6 +41,8 @@
41#include <subdev/gpio.h> 41#include <subdev/gpio.h>
42#include <engine/disp.h> 42#include <engine/disp.h>
43 43
44#include <core/class.h>
45
44static void 46static void
45nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) 47nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
46{ 48{
@@ -257,29 +259,10 @@ nouveau_display_fini(struct drm_device *dev)
257 disp->fini(dev); 259 disp->fini(dev);
258} 260}
259 261
260static void
261nouveau_display_vblank_notify(void *data, int crtc)
262{
263 drm_handle_vblank(data, crtc);
264}
265
266static void
267nouveau_display_vblank_get(void *data, int crtc)
268{
269 drm_vblank_get(data, crtc);
270}
271
272static void
273nouveau_display_vblank_put(void *data, int crtc)
274{
275 drm_vblank_put(data, crtc);
276}
277
278int 262int
279nouveau_display_create(struct drm_device *dev) 263nouveau_display_create(struct drm_device *dev)
280{ 264{
281 struct nouveau_drm *drm = nouveau_drm(dev); 265 struct nouveau_drm *drm = nouveau_drm(dev);
282 struct nouveau_disp *pdisp = nouveau_disp(drm->device);
283 struct nouveau_display *disp; 266 struct nouveau_display *disp;
284 u32 pclass = dev->pdev->class >> 8; 267 u32 pclass = dev->pdev->class >> 8;
285 int ret, gen; 268 int ret, gen;
@@ -288,11 +271,6 @@ nouveau_display_create(struct drm_device *dev)
288 if (!disp) 271 if (!disp)
289 return -ENOMEM; 272 return -ENOMEM;
290 273
291 pdisp->vblank.data = dev;
292 pdisp->vblank.notify = nouveau_display_vblank_notify;
293 pdisp->vblank.get = nouveau_display_vblank_get;
294 pdisp->vblank.put = nouveau_display_vblank_put;
295
296 drm_mode_config_init(dev); 274 drm_mode_config_init(dev);
297 drm_mode_create_scaling_mode_property(dev); 275 drm_mode_create_scaling_mode_property(dev);
298 drm_mode_create_dvi_i_properties(dev); 276 drm_mode_create_dvi_i_properties(dev);
@@ -474,39 +452,6 @@ nouveau_display_resume(struct drm_device *dev)
474 } 452 }
475} 453}
476 454
477int
478nouveau_vblank_enable(struct drm_device *dev, int crtc)
479{
480 struct nouveau_device *device = nouveau_dev(dev);
481
482 if (device->card_type >= NV_D0)
483 nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 1);
484 else
485 if (device->card_type >= NV_50)
486 nv_mask(device, NV50_PDISPLAY_INTR_EN_1, 0,
487 NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
488 else
489 NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
490 NV_PCRTC_INTR_0_VBLANK);
491
492 return 0;
493}
494
495void
496nouveau_vblank_disable(struct drm_device *dev, int crtc)
497{
498 struct nouveau_device *device = nouveau_dev(dev);
499
500 if (device->card_type >= NV_D0)
501 nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 0);
502 else
503 if (device->card_type >= NV_50)
504 nv_mask(device, NV50_PDISPLAY_INTR_EN_1,
505 NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
506 else
507 NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
508}
509
510static int 455static int
511nouveau_page_flip_reserve(struct nouveau_bo *old_bo, 456nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
512 struct nouveau_bo *new_bo) 457 struct nouveau_bo *new_bo)
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index 722548bb3bd3..1ea3e4734b62 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -59,9 +59,6 @@ void nouveau_display_fini(struct drm_device *dev);
59int nouveau_display_suspend(struct drm_device *dev); 59int nouveau_display_suspend(struct drm_device *dev);
60void nouveau_display_resume(struct drm_device *dev); 60void nouveau_display_resume(struct drm_device *dev);
61 61
62int nouveau_vblank_enable(struct drm_device *dev, int crtc);
63void nouveau_vblank_disable(struct drm_device *dev, int crtc);
64
65int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, 62int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
66 struct drm_pending_vblank_event *event); 63 struct drm_pending_vblank_event *event);
67int nouveau_finish_page_flip(struct nouveau_channel *, 64int nouveau_finish_page_flip(struct nouveau_channel *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index ef1ad21fd37f..ce91c8d43bb7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -34,6 +34,8 @@
34#include <subdev/device.h> 34#include <subdev/device.h>
35#include <subdev/vm.h> 35#include <subdev/vm.h>
36 36
37#include <engine/disp.h>
38
37#include "nouveau_drm.h" 39#include "nouveau_drm.h"
38#include "nouveau_irq.h" 40#include "nouveau_irq.h"
39#include "nouveau_dma.h" 41#include "nouveau_dma.h"
@@ -68,6 +70,32 @@ module_param_named(modeset, nouveau_modeset, int, 0400);
68 70
69static struct drm_driver driver; 71static struct drm_driver driver;
70 72
73static int
74nouveau_drm_vblank_enable(struct drm_device *dev, int head)
75{
76 struct nouveau_drm *drm = nouveau_drm(dev);
77 struct nouveau_disp *pdisp = nouveau_disp(drm->device);
78 nouveau_event_get(pdisp->vblank, head, &drm->vblank);
79 return 0;
80}
81
82static void
83nouveau_drm_vblank_disable(struct drm_device *dev, int head)
84{
85 struct nouveau_drm *drm = nouveau_drm(dev);
86 struct nouveau_disp *pdisp = nouveau_disp(drm->device);
87 nouveau_event_put(pdisp->vblank, head, &drm->vblank);
88}
89
90static int
91nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
92{
93 struct nouveau_drm *drm =
94 container_of(event, struct nouveau_drm, vblank);
95 drm_handle_vblank(drm->dev, head);
96 return NVKM_EVENT_KEEP;
97}
98
71static u64 99static u64
72nouveau_name(struct pci_dev *pdev) 100nouveau_name(struct pci_dev *pdev)
73{ 101{
@@ -259,6 +287,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
259 287
260 dev->dev_private = drm; 288 dev->dev_private = drm;
261 drm->dev = dev; 289 drm->dev = dev;
290 drm->vblank.func = nouveau_drm_vblank_handler;
262 291
263 INIT_LIST_HEAD(&drm->clients); 292 INIT_LIST_HEAD(&drm->clients);
264 spin_lock_init(&drm->tile.lock); 293 spin_lock_init(&drm->tile.lock);
@@ -643,8 +672,8 @@ driver = {
643 .irq_handler = nouveau_irq_handler, 672 .irq_handler = nouveau_irq_handler,
644 673
645 .get_vblank_counter = drm_vblank_count, 674 .get_vblank_counter = drm_vblank_count,
646 .enable_vblank = nouveau_vblank_enable, 675 .enable_vblank = nouveau_drm_vblank_enable,
647 .disable_vblank = nouveau_vblank_disable, 676 .disable_vblank = nouveau_drm_vblank_disable,
648 677
649 .ioctls = nouveau_ioctls, 678 .ioctls = nouveau_ioctls,
650 .fops = &nouveau_driver_fops, 679 .fops = &nouveau_driver_fops,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index aa89eb938b47..b25df374c901 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -13,6 +13,7 @@
13#define DRIVER_PATCHLEVEL 0 13#define DRIVER_PATCHLEVEL 0
14 14
15#include <core/client.h> 15#include <core/client.h>
16#include <core/event.h>
16 17
17#include <subdev/vm.h> 18#include <subdev/vm.h>
18 19
@@ -112,6 +113,7 @@ struct nouveau_drm {
112 struct nvbios vbios; 113 struct nvbios vbios;
113 struct nouveau_display *display; 114 struct nouveau_display *display;
114 struct backlight_device *backlight; 115 struct backlight_device *backlight;
116 struct nouveau_eventh vblank;
115 117
116 /* power management */ 118 /* power management */
117 struct nouveau_pm *pm; 119 struct nouveau_pm *pm;