aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-11-13 22:37:49 -0500
committerBen Skeggs <bskeggs@redhat.com>2014-01-29 18:20:27 -0500
commitd83ef85395c9c1fae7636dca59f95c64963b307d (patch)
tree883e6852c04d30c37d012aaad65da6db318e22e8
parentd2fa7d32ea7b54d910637e50df4972e3540722d4 (diff)
drm/nouveau: implement hooks for needed for drm vblank timestamping support
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c80
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c2
3 files changed, 86 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index b4262ad66b18..02a65259d8fb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -68,6 +68,86 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head)
68 nouveau_event_put(disp->vblank[head]); 68 nouveau_event_put(disp->vblank[head]);
69} 69}
70 70
71static inline int
72calc(int blanks, int blanke, int total, int line)
73{
74 if (blanke >= blanks) {
75 if (line >= blanks)
76 line -= total;
77 } else {
78 if (line >= blanks)
79 line -= total;
80 line -= blanke + 1;
81 }
82 return line;
83}
84
85int
86nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
87 ktime_t *stime, ktime_t *etime)
88{
89 const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index;
90 struct nouveau_display *disp = nouveau_display(crtc->dev);
91 struct nv04_display_scanoutpos args;
92 int ret, retry = 1;
93
94 do {
95 ret = nv_exec(disp->core, mthd, &args, sizeof(args));
96 if (ret != 0)
97 return 0;
98
99 if (args.vline) {
100 ret |= DRM_SCANOUTPOS_ACCURATE;
101 ret |= DRM_SCANOUTPOS_VALID;
102 break;
103 }
104
105 if (retry) ndelay(crtc->linedur_ns);
106 } while (retry--);
107
108 *hpos = calc(args.hblanks, args.hblanke, args.htotal, args.hline);
109 *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
110 if (stime) *stime = ns_to_ktime(args.time[0]);
111 if (etime) *etime = ns_to_ktime(args.time[1]);
112
113 if (*vpos < 0)
114 ret |= DRM_SCANOUTPOS_INVBL;
115 return ret;
116}
117
118int
119nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
120 int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
121{
122 struct drm_crtc *crtc;
123
124 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
125 if (nouveau_crtc(crtc)->index == head) {
126 return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
127 stime, etime);
128 }
129 }
130
131 return 0;
132}
133
134int
135nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error,
136 struct timeval *time, unsigned flags)
137{
138 struct drm_crtc *crtc;
139
140 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
141 if (nouveau_crtc(crtc)->index == head) {
142 return drm_calc_vbltimestamp_from_scanoutpos(dev,
143 head, max_error, time, flags, crtc,
144 &crtc->hwmode);
145 }
146 }
147
148 return -EINVAL;
149}
150
71static void 151static void
72nouveau_display_vblank_fini(struct drm_device *dev) 152nouveau_display_vblank_fini(struct drm_device *dev)
73{ 153{
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index 73aa231130b8..a71cf77e55b2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -64,6 +64,10 @@ void nouveau_display_repin(struct drm_device *dev);
64void nouveau_display_resume(struct drm_device *dev); 64void nouveau_display_resume(struct drm_device *dev);
65int nouveau_display_vblank_enable(struct drm_device *, int); 65int nouveau_display_vblank_enable(struct drm_device *, int);
66void nouveau_display_vblank_disable(struct drm_device *, int); 66void nouveau_display_vblank_disable(struct drm_device *, int);
67int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
68 int *, int *, ktime_t *, ktime_t *);
69int nouveau_display_vblstamp(struct drm_device *, int, int *,
70 struct timeval *, unsigned);
67 71
68int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, 72int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
69 struct drm_pending_vblank_event *event, 73 struct drm_pending_vblank_event *event,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 98a22e6e27a1..eecc6ca377c8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -798,6 +798,8 @@ driver = {
798 .get_vblank_counter = drm_vblank_count, 798 .get_vblank_counter = drm_vblank_count,
799 .enable_vblank = nouveau_display_vblank_enable, 799 .enable_vblank = nouveau_display_vblank_enable,
800 .disable_vblank = nouveau_display_vblank_disable, 800 .disable_vblank = nouveau_display_vblank_disable,
801 .get_scanout_position = nouveau_display_scanoutpos,
802 .get_vblank_timestamp = nouveau_display_vblstamp,
801 803
802 .ioctls = nouveau_ioctls, 804 .ioctls = nouveau_ioctls,
803 .num_ioctls = ARRAY_SIZE(nouveau_ioctls), 805 .num_ioctls = ARRAY_SIZE(nouveau_ioctls),