Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpu/drm/nouveau/nouveau_display.c
15112 views
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
#include "nv50_display.h"
36
37
static void
38
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
39
{
40
struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
41
42
if (fb->nvbo)
43
drm_gem_object_unreference_unlocked(fb->nvbo->gem);
44
45
drm_framebuffer_cleanup(drm_fb);
46
kfree(fb);
47
}
48
49
static int
50
nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
51
struct drm_file *file_priv,
52
unsigned int *handle)
53
{
54
struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
55
56
return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle);
57
}
58
59
static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
60
.destroy = nouveau_user_framebuffer_destroy,
61
.create_handle = nouveau_user_framebuffer_create_handle,
62
};
63
64
int
65
nouveau_framebuffer_init(struct drm_device *dev,
66
struct nouveau_framebuffer *nv_fb,
67
struct drm_mode_fb_cmd *mode_cmd,
68
struct nouveau_bo *nvbo)
69
{
70
struct drm_nouveau_private *dev_priv = dev->dev_private;
71
struct drm_framebuffer *fb = &nv_fb->base;
72
int ret;
73
74
ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
75
if (ret) {
76
return ret;
77
}
78
79
drm_helper_mode_fill_fb_struct(fb, mode_cmd);
80
nv_fb->nvbo = nvbo;
81
82
if (dev_priv->card_type >= NV_50) {
83
u32 tile_flags = nouveau_bo_tile_layout(nvbo);
84
if (tile_flags == 0x7a00 ||
85
tile_flags == 0xfe00)
86
nv_fb->r_dma = NvEvoFB32;
87
else
88
if (tile_flags == 0x7000)
89
nv_fb->r_dma = NvEvoFB16;
90
else
91
nv_fb->r_dma = NvEvoVRAM_LP;
92
93
switch (fb->depth) {
94
case 8: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_8; break;
95
case 15: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_15; break;
96
case 16: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_16; break;
97
case 24:
98
case 32: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_24; break;
99
case 30: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_30; break;
100
default:
101
NV_ERROR(dev, "unknown depth %d\n", fb->depth);
102
return -EINVAL;
103
}
104
105
if (dev_priv->chipset == 0x50)
106
nv_fb->r_format |= (tile_flags << 8);
107
108
if (!tile_flags)
109
nv_fb->r_pitch = 0x00100000 | fb->pitch;
110
else {
111
u32 mode = nvbo->tile_mode;
112
if (dev_priv->card_type >= NV_C0)
113
mode >>= 4;
114
nv_fb->r_pitch = ((fb->pitch / 4) << 4) | mode;
115
}
116
}
117
118
return 0;
119
}
120
121
static struct drm_framebuffer *
122
nouveau_user_framebuffer_create(struct drm_device *dev,
123
struct drm_file *file_priv,
124
struct drm_mode_fb_cmd *mode_cmd)
125
{
126
struct nouveau_framebuffer *nouveau_fb;
127
struct drm_gem_object *gem;
128
int ret;
129
130
gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
131
if (!gem)
132
return ERR_PTR(-ENOENT);
133
134
nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
135
if (!nouveau_fb)
136
return ERR_PTR(-ENOMEM);
137
138
ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
139
if (ret) {
140
drm_gem_object_unreference(gem);
141
return ERR_PTR(ret);
142
}
143
144
return &nouveau_fb->base;
145
}
146
147
const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
148
.fb_create = nouveau_user_framebuffer_create,
149
.output_poll_changed = nouveau_fbcon_output_poll_changed,
150
};
151
152
int
153
nouveau_vblank_enable(struct drm_device *dev, int crtc)
154
{
155
struct drm_nouveau_private *dev_priv = dev->dev_private;
156
157
if (dev_priv->card_type >= NV_50)
158
nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
159
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
160
else
161
NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
162
NV_PCRTC_INTR_0_VBLANK);
163
164
return 0;
165
}
166
167
void
168
nouveau_vblank_disable(struct drm_device *dev, int crtc)
169
{
170
struct drm_nouveau_private *dev_priv = dev->dev_private;
171
172
if (dev_priv->card_type >= NV_50)
173
nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
174
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
175
else
176
NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
177
}
178
179
static int
180
nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
181
struct nouveau_bo *new_bo)
182
{
183
int ret;
184
185
ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
186
if (ret)
187
return ret;
188
189
ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
190
if (ret)
191
goto fail;
192
193
ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
194
if (ret)
195
goto fail_unreserve;
196
197
return 0;
198
199
fail_unreserve:
200
ttm_bo_unreserve(&new_bo->bo);
201
fail:
202
nouveau_bo_unpin(new_bo);
203
return ret;
204
}
205
206
static void
207
nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
208
struct nouveau_bo *new_bo,
209
struct nouveau_fence *fence)
210
{
211
nouveau_bo_fence(new_bo, fence);
212
ttm_bo_unreserve(&new_bo->bo);
213
214
nouveau_bo_fence(old_bo, fence);
215
ttm_bo_unreserve(&old_bo->bo);
216
217
nouveau_bo_unpin(old_bo);
218
}
219
220
static int
221
nouveau_page_flip_emit(struct nouveau_channel *chan,
222
struct nouveau_bo *old_bo,
223
struct nouveau_bo *new_bo,
224
struct nouveau_page_flip_state *s,
225
struct nouveau_fence **pfence)
226
{
227
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
228
struct drm_device *dev = chan->dev;
229
unsigned long flags;
230
int ret;
231
232
/* Queue it to the pending list */
233
spin_lock_irqsave(&dev->event_lock, flags);
234
list_add_tail(&s->head, &chan->nvsw.flip);
235
spin_unlock_irqrestore(&dev->event_lock, flags);
236
237
/* Synchronize with the old framebuffer */
238
ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
239
if (ret)
240
goto fail;
241
242
/* Emit the pageflip */
243
ret = RING_SPACE(chan, 2);
244
if (ret)
245
goto fail;
246
247
if (dev_priv->card_type < NV_C0)
248
BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
249
else
250
BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0500, 1);
251
OUT_RING (chan, 0);
252
FIRE_RING (chan);
253
254
ret = nouveau_fence_new(chan, pfence, true);
255
if (ret)
256
goto fail;
257
258
return 0;
259
fail:
260
spin_lock_irqsave(&dev->event_lock, flags);
261
list_del(&s->head);
262
spin_unlock_irqrestore(&dev->event_lock, flags);
263
return ret;
264
}
265
266
int
267
nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
268
struct drm_pending_vblank_event *event)
269
{
270
struct drm_device *dev = crtc->dev;
271
struct drm_nouveau_private *dev_priv = dev->dev_private;
272
struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
273
struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
274
struct nouveau_page_flip_state *s;
275
struct nouveau_channel *chan;
276
struct nouveau_fence *fence;
277
int ret;
278
279
if (!dev_priv->channel)
280
return -ENODEV;
281
282
s = kzalloc(sizeof(*s), GFP_KERNEL);
283
if (!s)
284
return -ENOMEM;
285
286
/* Don't let the buffers go away while we flip */
287
ret = nouveau_page_flip_reserve(old_bo, new_bo);
288
if (ret)
289
goto fail_free;
290
291
/* Initialize a page flip struct */
292
*s = (struct nouveau_page_flip_state)
293
{ { }, event, nouveau_crtc(crtc)->index,
294
fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y,
295
new_bo->bo.offset };
296
297
/* Choose the channel the flip will be handled in */
298
chan = nouveau_fence_channel(new_bo->bo.sync_obj);
299
if (!chan)
300
chan = nouveau_channel_get_unlocked(dev_priv->channel);
301
mutex_lock(&chan->mutex);
302
303
/* Emit a page flip */
304
if (dev_priv->card_type >= NV_50) {
305
ret = nv50_display_flip_next(crtc, fb, chan);
306
if (ret) {
307
nouveau_channel_put(&chan);
308
goto fail_unreserve;
309
}
310
}
311
312
ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
313
nouveau_channel_put(&chan);
314
if (ret)
315
goto fail_unreserve;
316
317
/* Update the crtc struct and cleanup */
318
crtc->fb = fb;
319
320
nouveau_page_flip_unreserve(old_bo, new_bo, fence);
321
nouveau_fence_unref(&fence);
322
return 0;
323
324
fail_unreserve:
325
nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
326
fail_free:
327
kfree(s);
328
return ret;
329
}
330
331
int
332
nouveau_finish_page_flip(struct nouveau_channel *chan,
333
struct nouveau_page_flip_state *ps)
334
{
335
struct drm_device *dev = chan->dev;
336
struct nouveau_page_flip_state *s;
337
unsigned long flags;
338
339
spin_lock_irqsave(&dev->event_lock, flags);
340
341
if (list_empty(&chan->nvsw.flip)) {
342
NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
343
spin_unlock_irqrestore(&dev->event_lock, flags);
344
return -EINVAL;
345
}
346
347
s = list_first_entry(&chan->nvsw.flip,
348
struct nouveau_page_flip_state, head);
349
if (s->event) {
350
struct drm_pending_vblank_event *e = s->event;
351
struct timeval now;
352
353
do_gettimeofday(&now);
354
e->event.sequence = 0;
355
e->event.tv_sec = now.tv_sec;
356
e->event.tv_usec = now.tv_usec;
357
list_add_tail(&e->base.link, &e->base.file_priv->event_list);
358
wake_up_interruptible(&e->base.file_priv->event_wait);
359
}
360
361
list_del(&s->head);
362
if (ps)
363
*ps = *s;
364
kfree(s);
365
366
spin_unlock_irqrestore(&dev->event_lock, flags);
367
return 0;
368
}
369
370