1 /*
2  * Copyright (C) 2008 Maarten Maathuis.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include "drmP.h"
28 #include "drm_crtc_helper.h"
29 #include "nouveau_drv.h"
30 #include "nouveau_fb.h"
31 #include "nouveau_fbcon.h"
32 #include "nouveau_hw.h"
33 #include "nouveau_crtc.h"
34 #include "nouveau_dma.h"
35 
36 static void
37 nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
38 {
39 	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
40 
41 	if (fb->nvbo)
42 		drm_gem_object_unreference_unlocked(fb->nvbo->gem);
43 
44 	drm_framebuffer_cleanup(drm_fb);
45 	kfree(fb);
46 }
47 
48 static int
49 nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
50 				       struct drm_file *file_priv,
51 				       unsigned int *handle)
52 {
53 	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
54 
55 	return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle);
56 }
57 
58 static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
59 	.destroy = nouveau_user_framebuffer_destroy,
60 	.create_handle = nouveau_user_framebuffer_create_handle,
61 };
62 
63 int
64 nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
65 			 struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo)
66 {
67 	int ret;
68 
69 	ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs);
70 	if (ret) {
71 		return ret;
72 	}
73 
74 	drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd);
75 	nouveau_fb->nvbo = nvbo;
76 	return 0;
77 }
78 
79 static struct drm_framebuffer *
80 nouveau_user_framebuffer_create(struct drm_device *dev,
81 				struct drm_file *file_priv,
82 				struct drm_mode_fb_cmd *mode_cmd)
83 {
84 	struct nouveau_framebuffer *nouveau_fb;
85 	struct drm_gem_object *gem;
86 	int ret;
87 
88 	gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
89 	if (!gem)
90 		return ERR_PTR(-ENOENT);
91 
92 	nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
93 	if (!nouveau_fb)
94 		return ERR_PTR(-ENOMEM);
95 
96 	ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
97 	if (ret) {
98 		drm_gem_object_unreference(gem);
99 		return ERR_PTR(ret);
100 	}
101 
102 	return &nouveau_fb->base;
103 }
104 
105 const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
106 	.fb_create = nouveau_user_framebuffer_create,
107 	.output_poll_changed = nouveau_fbcon_output_poll_changed,
108 };
109 
110 int
111 nouveau_vblank_enable(struct drm_device *dev, int crtc)
112 {
113 	struct drm_nouveau_private *dev_priv = dev->dev_private;
114 
115 	if (dev_priv->card_type >= NV_50)
116 		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
117 			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
118 	else
119 		NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
120 			    NV_PCRTC_INTR_0_VBLANK);
121 
122 	return 0;
123 }
124 
125 void
126 nouveau_vblank_disable(struct drm_device *dev, int crtc)
127 {
128 	struct drm_nouveau_private *dev_priv = dev->dev_private;
129 
130 	if (dev_priv->card_type >= NV_50)
131 		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
132 			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
133 	else
134 		NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
135 }
136 
137 static int
138 nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
139 			  struct nouveau_bo *new_bo)
140 {
141 	int ret;
142 
143 	ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
144 	if (ret)
145 		return ret;
146 
147 	ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
148 	if (ret)
149 		goto fail;
150 
151 	ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
152 	if (ret)
153 		goto fail_unreserve;
154 
155 	return 0;
156 
157 fail_unreserve:
158 	ttm_bo_unreserve(&new_bo->bo);
159 fail:
160 	nouveau_bo_unpin(new_bo);
161 	return ret;
162 }
163 
164 static void
165 nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
166 			    struct nouveau_bo *new_bo,
167 			    struct nouveau_fence *fence)
168 {
169 	nouveau_bo_fence(new_bo, fence);
170 	ttm_bo_unreserve(&new_bo->bo);
171 
172 	nouveau_bo_fence(old_bo, fence);
173 	ttm_bo_unreserve(&old_bo->bo);
174 
175 	nouveau_bo_unpin(old_bo);
176 }
177 
178 static int
179 nouveau_page_flip_emit(struct nouveau_channel *chan,
180 		       struct nouveau_bo *old_bo,
181 		       struct nouveau_bo *new_bo,
182 		       struct nouveau_page_flip_state *s,
183 		       struct nouveau_fence **pfence)
184 {
185 	struct drm_device *dev = chan->dev;
186 	unsigned long flags;
187 	int ret;
188 
189 	/* Queue it to the pending list */
190 	spin_lock_irqsave(&dev->event_lock, flags);
191 	list_add_tail(&s->head, &chan->nvsw.flip);
192 	spin_unlock_irqrestore(&dev->event_lock, flags);
193 
194 	/* Synchronize with the old framebuffer */
195 	ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
196 	if (ret)
197 		goto fail;
198 
199 	/* Emit the pageflip */
200 	ret = RING_SPACE(chan, 2);
201 	if (ret)
202 		goto fail;
203 
204 	BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
205 	OUT_RING(chan, 0);
206 	FIRE_RING(chan);
207 
208 	ret = nouveau_fence_new(chan, pfence, true);
209 	if (ret)
210 		goto fail;
211 
212 	return 0;
213 fail:
214 	spin_lock_irqsave(&dev->event_lock, flags);
215 	list_del(&s->head);
216 	spin_unlock_irqrestore(&dev->event_lock, flags);
217 	return ret;
218 }
219 
220 int
221 nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
222 		       struct drm_pending_vblank_event *event)
223 {
224 	struct drm_device *dev = crtc->dev;
225 	struct drm_nouveau_private *dev_priv = dev->dev_private;
226 	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
227 	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
228 	struct nouveau_page_flip_state *s;
229 	struct nouveau_channel *chan;
230 	struct nouveau_fence *fence;
231 	int ret;
232 
233 	if (dev_priv->engine.graph.accel_blocked)
234 		return -ENODEV;
235 
236 	s = kzalloc(sizeof(*s), GFP_KERNEL);
237 	if (!s)
238 		return -ENOMEM;
239 
240 	/* Don't let the buffers go away while we flip */
241 	ret = nouveau_page_flip_reserve(old_bo, new_bo);
242 	if (ret)
243 		goto fail_free;
244 
245 	/* Initialize a page flip struct */
246 	*s = (struct nouveau_page_flip_state)
247 		{ { }, s->event, nouveau_crtc(crtc)->index,
248 		  fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y,
249 		  new_bo->bo.offset };
250 
251 	/* Choose the channel the flip will be handled in */
252 	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
253 	if (!chan)
254 		chan = nouveau_channel_get_unlocked(dev_priv->channel);
255 	mutex_lock(&chan->mutex);
256 
257 	/* Emit a page flip */
258 	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
259 	nouveau_channel_put(&chan);
260 	if (ret)
261 		goto fail_unreserve;
262 
263 	/* Update the crtc struct and cleanup */
264 	crtc->fb = fb;
265 
266 	nouveau_page_flip_unreserve(old_bo, new_bo, fence);
267 	nouveau_fence_unref(&fence);
268 	return 0;
269 
270 fail_unreserve:
271 	nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
272 fail_free:
273 	kfree(s);
274 	return ret;
275 }
276 
277 int
278 nouveau_finish_page_flip(struct nouveau_channel *chan,
279 			 struct nouveau_page_flip_state *ps)
280 {
281 	struct drm_device *dev = chan->dev;
282 	struct nouveau_page_flip_state *s;
283 	unsigned long flags;
284 
285 	spin_lock_irqsave(&dev->event_lock, flags);
286 
287 	if (list_empty(&chan->nvsw.flip)) {
288 		NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
289 		spin_unlock_irqrestore(&dev->event_lock, flags);
290 		return -EINVAL;
291 	}
292 
293 	s = list_first_entry(&chan->nvsw.flip,
294 			     struct nouveau_page_flip_state, head);
295 	if (s->event) {
296 		struct drm_pending_vblank_event *e = s->event;
297 		struct timeval now;
298 
299 		do_gettimeofday(&now);
300 		e->event.sequence = 0;
301 		e->event.tv_sec = now.tv_sec;
302 		e->event.tv_usec = now.tv_usec;
303 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
304 		wake_up_interruptible(&e->base.file_priv->event_wait);
305 	}
306 
307 	list_del(&s->head);
308 	*ps = *s;
309 	kfree(s);
310 
311 	spin_unlock_irqrestore(&dev->event_lock, flags);
312 	return 0;
313 }
314