diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 289 |
1 files changed, 144 insertions, 145 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 47ad74255bf1..1cc7b603c753 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <drm/drmP.h> | 27 | #include <drm/drmP.h> |
28 | #include <drm/drm_crtc_helper.h> | 28 | #include <drm/drm_crtc_helper.h> |
29 | 29 | ||
30 | #include <nvif/class.h> | ||
31 | |||
30 | #include "nouveau_fbcon.h" | 32 | #include "nouveau_fbcon.h" |
31 | #include "dispnv04/hw.h" | 33 | #include "dispnv04/hw.h" |
32 | #include "nouveau_crtc.h" | 34 | #include "nouveau_crtc.h" |
@@ -37,35 +39,42 @@ | |||
37 | 39 | ||
38 | #include "nouveau_fence.h" | 40 | #include "nouveau_fence.h" |
39 | 41 | ||
40 | #include <engine/disp.h> | 42 | #include <nvif/event.h> |
41 | |||
42 | #include <core/class.h> | ||
43 | 43 | ||
44 | static int | 44 | static int |
45 | nouveau_display_vblank_handler(void *data, u32 type, int head) | 45 | nouveau_display_vblank_handler(struct nvif_notify *notify) |
46 | { | 46 | { |
47 | struct nouveau_drm *drm = data; | 47 | struct nouveau_crtc *nv_crtc = |
48 | drm_handle_vblank(drm->dev, head); | 48 | container_of(notify, typeof(*nv_crtc), vblank); |
49 | return NVKM_EVENT_KEEP; | 49 | drm_handle_vblank(nv_crtc->base.dev, nv_crtc->index); |
50 | return NVIF_NOTIFY_KEEP; | ||
50 | } | 51 | } |
51 | 52 | ||
52 | int | 53 | int |
53 | nouveau_display_vblank_enable(struct drm_device *dev, int head) | 54 | nouveau_display_vblank_enable(struct drm_device *dev, int head) |
54 | { | 55 | { |
55 | struct nouveau_display *disp = nouveau_display(dev); | 56 | struct drm_crtc *crtc; |
56 | if (disp) { | 57 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
57 | nouveau_event_get(disp->vblank[head]); | 58 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
58 | return 0; | 59 | if (nv_crtc->index == head) { |
60 | nvif_notify_get(&nv_crtc->vblank); | ||
61 | return 0; | ||
62 | } | ||
59 | } | 63 | } |
60 | return -EIO; | 64 | return -EINVAL; |
61 | } | 65 | } |
62 | 66 | ||
63 | void | 67 | void |
64 | nouveau_display_vblank_disable(struct drm_device *dev, int head) | 68 | nouveau_display_vblank_disable(struct drm_device *dev, int head) |
65 | { | 69 | { |
66 | struct nouveau_display *disp = nouveau_display(dev); | 70 | struct drm_crtc *crtc; |
67 | if (disp) | 71 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
68 | nouveau_event_put(disp->vblank[head]); | 72 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
73 | if (nv_crtc->index == head) { | ||
74 | nvif_notify_put(&nv_crtc->vblank); | ||
75 | return; | ||
76 | } | ||
77 | } | ||
69 | } | 78 | } |
70 | 79 | ||
71 | static inline int | 80 | static inline int |
@@ -86,17 +95,22 @@ int | |||
86 | nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | 95 | nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, |
87 | ktime_t *stime, ktime_t *etime) | 96 | ktime_t *stime, ktime_t *etime) |
88 | { | 97 | { |
89 | const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index; | 98 | struct { |
99 | struct nv04_disp_mthd_v0 base; | ||
100 | struct nv04_disp_scanoutpos_v0 scan; | ||
101 | } args = { | ||
102 | .base.method = NV04_DISP_SCANOUTPOS, | ||
103 | .base.head = nouveau_crtc(crtc)->index, | ||
104 | }; | ||
90 | struct nouveau_display *disp = nouveau_display(crtc->dev); | 105 | struct nouveau_display *disp = nouveau_display(crtc->dev); |
91 | struct nv04_display_scanoutpos args; | ||
92 | int ret, retry = 1; | 106 | int ret, retry = 1; |
93 | 107 | ||
94 | do { | 108 | do { |
95 | ret = nv_exec(disp->core, mthd, &args, sizeof(args)); | 109 | ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); |
96 | if (ret != 0) | 110 | if (ret != 0) |
97 | return 0; | 111 | return 0; |
98 | 112 | ||
99 | if (args.vline) { | 113 | if (args.scan.vline) { |
100 | ret |= DRM_SCANOUTPOS_ACCURATE; | 114 | ret |= DRM_SCANOUTPOS_ACCURATE; |
101 | ret |= DRM_SCANOUTPOS_VALID; | 115 | ret |= DRM_SCANOUTPOS_VALID; |
102 | break; | 116 | break; |
@@ -105,10 +119,11 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
105 | if (retry) ndelay(crtc->linedur_ns); | 119 | if (retry) ndelay(crtc->linedur_ns); |
106 | } while (retry--); | 120 | } while (retry--); |
107 | 121 | ||
108 | *hpos = args.hline; | 122 | *hpos = args.scan.hline; |
109 | *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); | 123 | *vpos = calc(args.scan.vblanks, args.scan.vblanke, |
110 | if (stime) *stime = ns_to_ktime(args.time[0]); | 124 | args.scan.vtotal, args.scan.vline); |
111 | if (etime) *etime = ns_to_ktime(args.time[1]); | 125 | if (stime) *stime = ns_to_ktime(args.scan.time[0]); |
126 | if (etime) *etime = ns_to_ktime(args.scan.time[1]); | ||
112 | 127 | ||
113 | if (*vpos < 0) | 128 | if (*vpos < 0) |
114 | ret |= DRM_SCANOUTPOS_INVBL; | 129 | ret |= DRM_SCANOUTPOS_INVBL; |
@@ -151,16 +166,13 @@ nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error, | |||
151 | static void | 166 | static void |
152 | nouveau_display_vblank_fini(struct drm_device *dev) | 167 | nouveau_display_vblank_fini(struct drm_device *dev) |
153 | { | 168 | { |
154 | struct nouveau_display *disp = nouveau_display(dev); | 169 | struct drm_crtc *crtc; |
155 | int i; | ||
156 | 170 | ||
157 | drm_vblank_cleanup(dev); | 171 | drm_vblank_cleanup(dev); |
158 | 172 | ||
159 | if (disp->vblank) { | 173 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
160 | for (i = 0; i < dev->mode_config.num_crtc; i++) | 174 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
161 | nouveau_event_ref(NULL, &disp->vblank[i]); | 175 | nvif_notify_fini(&nv_crtc->vblank); |
162 | kfree(disp->vblank); | ||
163 | disp->vblank = NULL; | ||
164 | } | 176 | } |
165 | } | 177 | } |
166 | 178 | ||
@@ -168,19 +180,20 @@ static int | |||
168 | nouveau_display_vblank_init(struct drm_device *dev) | 180 | nouveau_display_vblank_init(struct drm_device *dev) |
169 | { | 181 | { |
170 | struct nouveau_display *disp = nouveau_display(dev); | 182 | struct nouveau_display *disp = nouveau_display(dev); |
171 | struct nouveau_drm *drm = nouveau_drm(dev); | 183 | struct drm_crtc *crtc; |
172 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); | 184 | int ret; |
173 | int ret, i; | ||
174 | |||
175 | disp->vblank = kzalloc(dev->mode_config.num_crtc * | ||
176 | sizeof(*disp->vblank), GFP_KERNEL); | ||
177 | if (!disp->vblank) | ||
178 | return -ENOMEM; | ||
179 | 185 | ||
180 | for (i = 0; i < dev->mode_config.num_crtc; i++) { | 186 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
181 | ret = nouveau_event_new(pdisp->vblank, 1, i, | 187 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
182 | nouveau_display_vblank_handler, | 188 | ret = nvif_notify_init(&disp->disp, NULL, |
183 | drm, &disp->vblank[i]); | 189 | nouveau_display_vblank_handler, false, |
190 | NV04_DISP_NTFY_VBLANK, | ||
191 | &(struct nvif_notify_head_req_v0) { | ||
192 | .head = nv_crtc->index, | ||
193 | }, | ||
194 | sizeof(struct nvif_notify_head_req_v0), | ||
195 | sizeof(struct nvif_notify_head_rep_v0), | ||
196 | &nv_crtc->vblank); | ||
184 | if (ret) { | 197 | if (ret) { |
185 | nouveau_display_vblank_fini(dev); | 198 | nouveau_display_vblank_fini(dev); |
186 | return ret; | 199 | return ret; |
@@ -200,6 +213,10 @@ static void | |||
200 | nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) | 213 | nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) |
201 | { | 214 | { |
202 | struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); | 215 | struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); |
216 | struct nouveau_display *disp = nouveau_display(drm_fb->dev); | ||
217 | |||
218 | if (disp->fb_dtor) | ||
219 | disp->fb_dtor(drm_fb); | ||
203 | 220 | ||
204 | if (fb->nvbo) | 221 | if (fb->nvbo) |
205 | drm_gem_object_unreference_unlocked(&fb->nvbo->gem); | 222 | drm_gem_object_unreference_unlocked(&fb->nvbo->gem); |
@@ -229,63 +246,24 @@ nouveau_framebuffer_init(struct drm_device *dev, | |||
229 | struct drm_mode_fb_cmd2 *mode_cmd, | 246 | struct drm_mode_fb_cmd2 *mode_cmd, |
230 | struct nouveau_bo *nvbo) | 247 | struct nouveau_bo *nvbo) |
231 | { | 248 | { |
232 | struct nouveau_drm *drm = nouveau_drm(dev); | 249 | struct nouveau_display *disp = nouveau_display(dev); |
233 | struct drm_framebuffer *fb = &nv_fb->base; | 250 | struct drm_framebuffer *fb = &nv_fb->base; |
234 | int ret; | 251 | int ret; |
235 | 252 | ||
236 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); | 253 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); |
237 | nv_fb->nvbo = nvbo; | 254 | nv_fb->nvbo = nvbo; |
238 | 255 | ||
239 | if (nv_device(drm->device)->card_type >= NV_50) { | ||
240 | u32 tile_flags = nouveau_bo_tile_layout(nvbo); | ||
241 | if (tile_flags == 0x7a00 || | ||
242 | tile_flags == 0xfe00) | ||
243 | nv_fb->r_dma = NvEvoFB32; | ||
244 | else | ||
245 | if (tile_flags == 0x7000) | ||
246 | nv_fb->r_dma = NvEvoFB16; | ||
247 | else | ||
248 | nv_fb->r_dma = NvEvoVRAM_LP; | ||
249 | |||
250 | switch (fb->depth) { | ||
251 | case 8: nv_fb->r_format = 0x1e00; break; | ||
252 | case 15: nv_fb->r_format = 0xe900; break; | ||
253 | case 16: nv_fb->r_format = 0xe800; break; | ||
254 | case 24: | ||
255 | case 32: nv_fb->r_format = 0xcf00; break; | ||
256 | case 30: nv_fb->r_format = 0xd100; break; | ||
257 | default: | ||
258 | NV_ERROR(drm, "unknown depth %d\n", fb->depth); | ||
259 | return -EINVAL; | ||
260 | } | ||
261 | |||
262 | if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) { | ||
263 | NV_ERROR(drm, "framebuffer requires contiguous bo\n"); | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | if (nv_device(drm->device)->chipset == 0x50) | ||
268 | nv_fb->r_format |= (tile_flags << 8); | ||
269 | |||
270 | if (!tile_flags) { | ||
271 | if (nv_device(drm->device)->card_type < NV_D0) | ||
272 | nv_fb->r_pitch = 0x00100000 | fb->pitches[0]; | ||
273 | else | ||
274 | nv_fb->r_pitch = 0x01000000 | fb->pitches[0]; | ||
275 | } else { | ||
276 | u32 mode = nvbo->tile_mode; | ||
277 | if (nv_device(drm->device)->card_type >= NV_C0) | ||
278 | mode >>= 4; | ||
279 | nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); | 256 | ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); |
284 | if (ret) { | 257 | if (ret) |
285 | return ret; | 258 | return ret; |
259 | |||
260 | if (disp->fb_ctor) { | ||
261 | ret = disp->fb_ctor(fb); | ||
262 | if (ret) | ||
263 | disp->fb_dtor(fb); | ||
286 | } | 264 | } |
287 | 265 | ||
288 | return 0; | 266 | return ret; |
289 | } | 267 | } |
290 | 268 | ||
291 | static struct drm_framebuffer * | 269 | static struct drm_framebuffer * |
@@ -393,7 +371,7 @@ nouveau_display_init(struct drm_device *dev) | |||
393 | /* enable hotplug interrupts */ | 371 | /* enable hotplug interrupts */ |
394 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 372 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
395 | struct nouveau_connector *conn = nouveau_connector(connector); | 373 | struct nouveau_connector *conn = nouveau_connector(connector); |
396 | if (conn->hpd) nouveau_event_get(conn->hpd); | 374 | nvif_notify_get(&conn->hpd); |
397 | } | 375 | } |
398 | 376 | ||
399 | return ret; | 377 | return ret; |
@@ -404,37 +382,32 @@ nouveau_display_fini(struct drm_device *dev) | |||
404 | { | 382 | { |
405 | struct nouveau_display *disp = nouveau_display(dev); | 383 | struct nouveau_display *disp = nouveau_display(dev); |
406 | struct drm_connector *connector; | 384 | struct drm_connector *connector; |
385 | int head; | ||
386 | |||
387 | /* Make sure that drm and hw vblank irqs get properly disabled. */ | ||
388 | for (head = 0; head < dev->mode_config.num_crtc; head++) | ||
389 | drm_vblank_off(dev, head); | ||
407 | 390 | ||
408 | /* disable hotplug interrupts */ | 391 | /* disable hotplug interrupts */ |
409 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 392 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
410 | struct nouveau_connector *conn = nouveau_connector(connector); | 393 | struct nouveau_connector *conn = nouveau_connector(connector); |
411 | if (conn->hpd) nouveau_event_put(conn->hpd); | 394 | nvif_notify_put(&conn->hpd); |
412 | } | 395 | } |
413 | 396 | ||
414 | drm_kms_helper_poll_disable(dev); | 397 | drm_kms_helper_poll_disable(dev); |
415 | disp->fini(dev); | 398 | disp->fini(dev); |
416 | } | 399 | } |
417 | 400 | ||
418 | int | 401 | static void |
419 | nouveau_display_create(struct drm_device *dev) | 402 | nouveau_display_create_properties(struct drm_device *dev) |
420 | { | 403 | { |
421 | struct nouveau_drm *drm = nouveau_drm(dev); | 404 | struct nouveau_display *disp = nouveau_display(dev); |
422 | struct nouveau_device *device = nouveau_dev(dev); | 405 | int gen; |
423 | struct nouveau_display *disp; | ||
424 | int ret, gen; | ||
425 | |||
426 | disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); | ||
427 | if (!disp) | ||
428 | return -ENOMEM; | ||
429 | |||
430 | drm_mode_config_init(dev); | ||
431 | drm_mode_create_scaling_mode_property(dev); | ||
432 | drm_mode_create_dvi_i_properties(dev); | ||
433 | 406 | ||
434 | if (nv_device(drm->device)->card_type < NV_50) | 407 | if (disp->disp.oclass < NV50_DISP) |
435 | gen = 0; | 408 | gen = 0; |
436 | else | 409 | else |
437 | if (nv_device(drm->device)->card_type < NV_D0) | 410 | if (disp->disp.oclass < GF110_DISP) |
438 | gen = 1; | 411 | gen = 1; |
439 | else | 412 | else |
440 | gen = 2; | 413 | gen = 2; |
@@ -449,26 +422,43 @@ nouveau_display_create(struct drm_device *dev) | |||
449 | disp->underscan_vborder_property = | 422 | disp->underscan_vborder_property = |
450 | drm_property_create_range(dev, 0, "underscan vborder", 0, 128); | 423 | drm_property_create_range(dev, 0, "underscan vborder", 0, 128); |
451 | 424 | ||
452 | if (gen >= 1) { | 425 | if (gen < 1) |
453 | /* -90..+90 */ | 426 | return; |
454 | disp->vibrant_hue_property = | ||
455 | drm_property_create_range(dev, 0, "vibrant hue", 0, 180); | ||
456 | 427 | ||
457 | /* -100..+100 */ | 428 | /* -90..+90 */ |
458 | disp->color_vibrance_property = | 429 | disp->vibrant_hue_property = |
459 | drm_property_create_range(dev, 0, "color vibrance", 0, 200); | 430 | drm_property_create_range(dev, 0, "vibrant hue", 0, 180); |
460 | } | 431 | |
432 | /* -100..+100 */ | ||
433 | disp->color_vibrance_property = | ||
434 | drm_property_create_range(dev, 0, "color vibrance", 0, 200); | ||
435 | } | ||
436 | |||
437 | int | ||
438 | nouveau_display_create(struct drm_device *dev) | ||
439 | { | ||
440 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
441 | struct nouveau_display *disp; | ||
442 | int ret; | ||
443 | |||
444 | disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); | ||
445 | if (!disp) | ||
446 | return -ENOMEM; | ||
447 | |||
448 | drm_mode_config_init(dev); | ||
449 | drm_mode_create_scaling_mode_property(dev); | ||
450 | drm_mode_create_dvi_i_properties(dev); | ||
461 | 451 | ||
462 | dev->mode_config.funcs = &nouveau_mode_config_funcs; | 452 | dev->mode_config.funcs = &nouveau_mode_config_funcs; |
463 | dev->mode_config.fb_base = nv_device_resource_start(device, 1); | 453 | dev->mode_config.fb_base = nv_device_resource_start(nvkm_device(&drm->device), 1); |
464 | 454 | ||
465 | dev->mode_config.min_width = 0; | 455 | dev->mode_config.min_width = 0; |
466 | dev->mode_config.min_height = 0; | 456 | dev->mode_config.min_height = 0; |
467 | if (nv_device(drm->device)->card_type < NV_10) { | 457 | if (drm->device.info.family < NV_DEVICE_INFO_V0_CELSIUS) { |
468 | dev->mode_config.max_width = 2048; | 458 | dev->mode_config.max_width = 2048; |
469 | dev->mode_config.max_height = 2048; | 459 | dev->mode_config.max_height = 2048; |
470 | } else | 460 | } else |
471 | if (nv_device(drm->device)->card_type < NV_50) { | 461 | if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { |
472 | dev->mode_config.max_width = 4096; | 462 | dev->mode_config.max_width = 4096; |
473 | dev->mode_config.max_height = 4096; | 463 | dev->mode_config.max_height = 4096; |
474 | } else { | 464 | } else { |
@@ -479,7 +469,7 @@ nouveau_display_create(struct drm_device *dev) | |||
479 | dev->mode_config.preferred_depth = 24; | 469 | dev->mode_config.preferred_depth = 24; |
480 | dev->mode_config.prefer_shadow = 1; | 470 | dev->mode_config.prefer_shadow = 1; |
481 | 471 | ||
482 | if (nv_device(drm->device)->chipset < 0x11) | 472 | if (drm->device.info.chipset < 0x11) |
483 | dev->mode_config.async_page_flip = false; | 473 | dev->mode_config.async_page_flip = false; |
484 | else | 474 | else |
485 | dev->mode_config.async_page_flip = true; | 475 | dev->mode_config.async_page_flip = true; |
@@ -487,29 +477,30 @@ nouveau_display_create(struct drm_device *dev) | |||
487 | drm_kms_helper_poll_init(dev); | 477 | drm_kms_helper_poll_init(dev); |
488 | drm_kms_helper_poll_disable(dev); | 478 | drm_kms_helper_poll_disable(dev); |
489 | 479 | ||
490 | if (drm->vbios.dcb.entries) { | 480 | if (nouveau_modeset != 2 && drm->vbios.dcb.entries) { |
491 | static const u16 oclass[] = { | 481 | static const u16 oclass[] = { |
492 | GM107_DISP_CLASS, | 482 | GM107_DISP, |
493 | NVF0_DISP_CLASS, | 483 | GK110_DISP, |
494 | NVE0_DISP_CLASS, | 484 | GK104_DISP, |
495 | NVD0_DISP_CLASS, | 485 | GF110_DISP, |
496 | NVA3_DISP_CLASS, | 486 | GT214_DISP, |
497 | NV94_DISP_CLASS, | 487 | GT206_DISP, |
498 | NVA0_DISP_CLASS, | 488 | GT200_DISP, |
499 | NV84_DISP_CLASS, | 489 | G82_DISP, |
500 | NV50_DISP_CLASS, | 490 | NV50_DISP, |
501 | NV04_DISP_CLASS, | 491 | NV04_DISP, |
502 | }; | 492 | }; |
503 | int i; | 493 | int i; |
504 | 494 | ||
505 | for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) { | 495 | for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) { |
506 | ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, | 496 | ret = nvif_object_init(nvif_object(&drm->device), NULL, |
507 | NVDRM_DISPLAY, oclass[i], | 497 | NVDRM_DISPLAY, oclass[i], |
508 | NULL, 0, &disp->core); | 498 | NULL, 0, &disp->disp); |
509 | } | 499 | } |
510 | 500 | ||
511 | if (ret == 0) { | 501 | if (ret == 0) { |
512 | if (nv_mclass(disp->core) < NV50_DISP_CLASS) | 502 | nouveau_display_create_properties(dev); |
503 | if (disp->disp.oclass < NV50_DISP) | ||
513 | ret = nv04_display_create(dev); | 504 | ret = nv04_display_create(dev); |
514 | else | 505 | else |
515 | ret = nv50_display_create(dev); | 506 | ret = nv50_display_create(dev); |
@@ -542,7 +533,6 @@ void | |||
542 | nouveau_display_destroy(struct drm_device *dev) | 533 | nouveau_display_destroy(struct drm_device *dev) |
543 | { | 534 | { |
544 | struct nouveau_display *disp = nouveau_display(dev); | 535 | struct nouveau_display *disp = nouveau_display(dev); |
545 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
546 | 536 | ||
547 | nouveau_backlight_exit(dev); | 537 | nouveau_backlight_exit(dev); |
548 | nouveau_display_vblank_fini(dev); | 538 | nouveau_display_vblank_fini(dev); |
@@ -553,7 +543,7 @@ nouveau_display_destroy(struct drm_device *dev) | |||
553 | if (disp->dtor) | 543 | if (disp->dtor) |
554 | disp->dtor(dev); | 544 | disp->dtor(dev); |
555 | 545 | ||
556 | nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_DISPLAY); | 546 | nvif_object_fini(&disp->disp); |
557 | 547 | ||
558 | nouveau_drm(dev)->display = NULL; | 548 | nouveau_drm(dev)->display = NULL; |
559 | kfree(disp); | 549 | kfree(disp); |
@@ -620,6 +610,8 @@ void | |||
620 | nouveau_display_resume(struct drm_device *dev) | 610 | nouveau_display_resume(struct drm_device *dev) |
621 | { | 611 | { |
622 | struct drm_crtc *crtc; | 612 | struct drm_crtc *crtc; |
613 | int head; | ||
614 | |||
623 | nouveau_display_init(dev); | 615 | nouveau_display_init(dev); |
624 | 616 | ||
625 | /* Force CLUT to get re-loaded during modeset */ | 617 | /* Force CLUT to get re-loaded during modeset */ |
@@ -629,6 +621,10 @@ nouveau_display_resume(struct drm_device *dev) | |||
629 | nv_crtc->lut.depth = 0; | 621 | nv_crtc->lut.depth = 0; |
630 | } | 622 | } |
631 | 623 | ||
624 | /* Make sure that drm and hw vblank irqs get resumed if needed. */ | ||
625 | for (head = 0; head < dev->mode_config.num_crtc; head++) | ||
626 | drm_vblank_on(dev, head); | ||
627 | |||
632 | drm_helper_resume_force_mode(dev); | 628 | drm_helper_resume_force_mode(dev); |
633 | 629 | ||
634 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 630 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
@@ -669,7 +665,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, | |||
669 | if (ret) | 665 | if (ret) |
670 | goto fail; | 666 | goto fail; |
671 | 667 | ||
672 | if (nv_device(drm->device)->card_type < NV_C0) | 668 | if (drm->device.info.family < NV_DEVICE_INFO_V0_FERMI) |
673 | BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); | 669 | BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); |
674 | else | 670 | else |
675 | BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1); | 671 | BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1); |
@@ -698,12 +694,15 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
698 | struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; | 694 | struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; |
699 | struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; | 695 | struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; |
700 | struct nouveau_page_flip_state *s; | 696 | struct nouveau_page_flip_state *s; |
701 | struct nouveau_channel *chan = drm->channel; | 697 | struct nouveau_channel *chan; |
698 | struct nouveau_cli *cli; | ||
702 | struct nouveau_fence *fence; | 699 | struct nouveau_fence *fence; |
703 | int ret; | 700 | int ret; |
704 | 701 | ||
705 | if (!drm->channel) | 702 | chan = drm->channel; |
703 | if (!chan) | ||
706 | return -ENODEV; | 704 | return -ENODEV; |
705 | cli = (void *)nvif_client(&chan->device->base); | ||
707 | 706 | ||
708 | s = kzalloc(sizeof(*s), GFP_KERNEL); | 707 | s = kzalloc(sizeof(*s), GFP_KERNEL); |
709 | if (!s) | 708 | if (!s) |
@@ -715,7 +714,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
715 | goto fail_free; | 714 | goto fail_free; |
716 | } | 715 | } |
717 | 716 | ||
718 | mutex_lock(&chan->cli->mutex); | 717 | mutex_lock(&cli->mutex); |
719 | 718 | ||
720 | /* synchronise rendering channel with the kernel's channel */ | 719 | /* synchronise rendering channel with the kernel's channel */ |
721 | spin_lock(&new_bo->bo.bdev->fence_lock); | 720 | spin_lock(&new_bo->bo.bdev->fence_lock); |
@@ -740,7 +739,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
740 | drm_vblank_get(dev, nouveau_crtc(crtc)->index); | 739 | drm_vblank_get(dev, nouveau_crtc(crtc)->index); |
741 | 740 | ||
742 | /* Emit a page flip */ | 741 | /* Emit a page flip */ |
743 | if (nv_device(drm->device)->card_type >= NV_50) { | 742 | if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { |
744 | ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); | 743 | ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); |
745 | if (ret) | 744 | if (ret) |
746 | goto fail_unreserve; | 745 | goto fail_unreserve; |
@@ -769,7 +768,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
769 | ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); | 768 | ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); |
770 | if (ret) | 769 | if (ret) |
771 | goto fail_unreserve; | 770 | goto fail_unreserve; |
772 | mutex_unlock(&chan->cli->mutex); | 771 | mutex_unlock(&cli->mutex); |
773 | 772 | ||
774 | /* Update the crtc struct and cleanup */ | 773 | /* Update the crtc struct and cleanup */ |
775 | crtc->primary->fb = fb; | 774 | crtc->primary->fb = fb; |
@@ -785,7 +784,7 @@ fail_unreserve: | |||
785 | drm_vblank_put(dev, nouveau_crtc(crtc)->index); | 784 | drm_vblank_put(dev, nouveau_crtc(crtc)->index); |
786 | ttm_bo_unreserve(&old_bo->bo); | 785 | ttm_bo_unreserve(&old_bo->bo); |
787 | fail_unpin: | 786 | fail_unpin: |
788 | mutex_unlock(&chan->cli->mutex); | 787 | mutex_unlock(&cli->mutex); |
789 | if (old_bo != new_bo) | 788 | if (old_bo != new_bo) |
790 | nouveau_bo_unpin(new_bo); | 789 | nouveau_bo_unpin(new_bo); |
791 | fail_free: | 790 | fail_free: |
@@ -815,7 +814,7 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, | |||
815 | s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); | 814 | s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); |
816 | if (s->event) { | 815 | if (s->event) { |
817 | /* Vblank timestamps/counts are only correct on >= NV-50 */ | 816 | /* Vblank timestamps/counts are only correct on >= NV-50 */ |
818 | if (nv_device(drm->device)->card_type >= NV_50) | 817 | if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) |
819 | crtcid = s->crtc; | 818 | crtcid = s->crtc; |
820 | 819 | ||
821 | drm_send_vblank_event(dev, crtcid, s->event); | 820 | drm_send_vblank_event(dev, crtcid, s->event); |
@@ -841,7 +840,7 @@ nouveau_flip_complete(void *data) | |||
841 | struct nouveau_page_flip_state state; | 840 | struct nouveau_page_flip_state state; |
842 | 841 | ||
843 | if (!nouveau_finish_page_flip(chan, &state)) { | 842 | if (!nouveau_finish_page_flip(chan, &state)) { |
844 | if (nv_device(drm->device)->card_type < NV_50) { | 843 | if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { |
845 | nv_set_crtc_base(drm->dev, state.crtc, state.offset + | 844 | nv_set_crtc_base(drm->dev, state.crtc, state.offset + |
846 | state.y * state.pitch + | 845 | state.y * state.pitch + |
847 | state.x * state.bpp / 8); | 846 | state.x * state.bpp / 8); |