diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-11-13 22:37:49 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-01-29 18:20:27 -0500 |
commit | d83ef85395c9c1fae7636dca59f95c64963b307d (patch) | |
tree | 883e6852c04d30c37d012aaad65da6db318e22e8 | |
parent | d2fa7d32ea7b54d910637e50df4972e3540722d4 (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.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 2 |
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 | ||
71 | static inline int | ||
72 | calc(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 | |||
85 | int | ||
86 | nouveau_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 | |||
118 | int | ||
119 | nouveau_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 | |||
134 | int | ||
135 | nouveau_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 | |||
71 | static void | 151 | static void |
72 | nouveau_display_vblank_fini(struct drm_device *dev) | 152 | nouveau_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); | |||
64 | void nouveau_display_resume(struct drm_device *dev); | 64 | void nouveau_display_resume(struct drm_device *dev); |
65 | int nouveau_display_vblank_enable(struct drm_device *, int); | 65 | int nouveau_display_vblank_enable(struct drm_device *, int); |
66 | void nouveau_display_vblank_disable(struct drm_device *, int); | 66 | void nouveau_display_vblank_disable(struct drm_device *, int); |
67 | int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, | ||
68 | int *, int *, ktime_t *, ktime_t *); | ||
69 | int nouveau_display_vblstamp(struct drm_device *, int, int *, | ||
70 | struct timeval *, unsigned); | ||
67 | 71 | ||
68 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | 72 | int 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), |