diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 40 |
1 files changed, 26 insertions, 14 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index a85e112863d1..69688ef5cf46 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -33,7 +33,9 @@ | |||
33 | #include "nouveau_crtc.h" | 33 | #include "nouveau_crtc.h" |
34 | #include "nouveau_dma.h" | 34 | #include "nouveau_dma.h" |
35 | #include "nouveau_connector.h" | 35 | #include "nouveau_connector.h" |
36 | #include "nouveau_software.h" | ||
36 | #include "nouveau_gpio.h" | 37 | #include "nouveau_gpio.h" |
38 | #include "nouveau_fence.h" | ||
37 | #include "nv50_display.h" | 39 | #include "nv50_display.h" |
38 | 40 | ||
39 | static void | 41 | static void |
@@ -300,7 +302,7 @@ nouveau_display_create(struct drm_device *dev) | |||
300 | disp->color_vibrance_property->values[1] = 200; /* -100..+100 */ | 302 | disp->color_vibrance_property->values[1] = 200; /* -100..+100 */ |
301 | } | 303 | } |
302 | 304 | ||
303 | dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; | 305 | dev->mode_config.funcs = &nouveau_mode_config_funcs; |
304 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); | 306 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); |
305 | 307 | ||
306 | dev->mode_config.min_width = 0; | 308 | dev->mode_config.min_width = 0; |
@@ -325,14 +327,21 @@ nouveau_display_create(struct drm_device *dev) | |||
325 | 327 | ||
326 | ret = disp->create(dev); | 328 | ret = disp->create(dev); |
327 | if (ret) | 329 | if (ret) |
328 | return ret; | 330 | goto disp_create_err; |
329 | 331 | ||
330 | if (dev->mode_config.num_crtc) { | 332 | if (dev->mode_config.num_crtc) { |
331 | ret = drm_vblank_init(dev, dev->mode_config.num_crtc); | 333 | ret = drm_vblank_init(dev, dev->mode_config.num_crtc); |
332 | if (ret) | 334 | if (ret) |
333 | return ret; | 335 | goto vblank_err; |
334 | } | 336 | } |
335 | 337 | ||
338 | return 0; | ||
339 | |||
340 | vblank_err: | ||
341 | disp->destroy(dev); | ||
342 | disp_create_err: | ||
343 | drm_kms_helper_poll_fini(dev); | ||
344 | drm_mode_config_cleanup(dev); | ||
336 | return ret; | 345 | return ret; |
337 | } | 346 | } |
338 | 347 | ||
@@ -425,6 +434,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, | |||
425 | struct nouveau_page_flip_state *s, | 434 | struct nouveau_page_flip_state *s, |
426 | struct nouveau_fence **pfence) | 435 | struct nouveau_fence **pfence) |
427 | { | 436 | { |
437 | struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW]; | ||
428 | struct drm_nouveau_private *dev_priv = chan->dev->dev_private; | 438 | struct drm_nouveau_private *dev_priv = chan->dev->dev_private; |
429 | struct drm_device *dev = chan->dev; | 439 | struct drm_device *dev = chan->dev; |
430 | unsigned long flags; | 440 | unsigned long flags; |
@@ -432,7 +442,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, | |||
432 | 442 | ||
433 | /* Queue it to the pending list */ | 443 | /* Queue it to the pending list */ |
434 | spin_lock_irqsave(&dev->event_lock, flags); | 444 | spin_lock_irqsave(&dev->event_lock, flags); |
435 | list_add_tail(&s->head, &chan->nvsw.flip); | 445 | list_add_tail(&s->head, &swch->flip); |
436 | spin_unlock_irqrestore(&dev->event_lock, flags); | 446 | spin_unlock_irqrestore(&dev->event_lock, flags); |
437 | 447 | ||
438 | /* Synchronize with the old framebuffer */ | 448 | /* Synchronize with the old framebuffer */ |
@@ -446,17 +456,17 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, | |||
446 | goto fail; | 456 | goto fail; |
447 | 457 | ||
448 | if (dev_priv->card_type < NV_C0) { | 458 | if (dev_priv->card_type < NV_C0) { |
449 | BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); | 459 | BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); |
450 | OUT_RING (chan, 0x00000000); | 460 | OUT_RING (chan, 0x00000000); |
451 | OUT_RING (chan, 0x00000000); | 461 | OUT_RING (chan, 0x00000000); |
452 | } else { | 462 | } else { |
453 | BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1); | 463 | BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1); |
454 | OUT_RING (chan, ++chan->fence.sequence); | 464 | OUT_RING (chan, 0); |
455 | BEGIN_NVC0(chan, 8, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000); | 465 | BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000); |
456 | } | 466 | } |
457 | FIRE_RING (chan); | 467 | FIRE_RING (chan); |
458 | 468 | ||
459 | ret = nouveau_fence_new(chan, pfence, true); | 469 | ret = nouveau_fence_new(chan, pfence); |
460 | if (ret) | 470 | if (ret) |
461 | goto fail; | 471 | goto fail; |
462 | 472 | ||
@@ -477,7 +487,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
477 | struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; | 487 | struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; |
478 | struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; | 488 | struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; |
479 | struct nouveau_page_flip_state *s; | 489 | struct nouveau_page_flip_state *s; |
480 | struct nouveau_channel *chan; | 490 | struct nouveau_channel *chan = NULL; |
481 | struct nouveau_fence *fence; | 491 | struct nouveau_fence *fence; |
482 | int ret; | 492 | int ret; |
483 | 493 | ||
@@ -500,7 +510,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
500 | new_bo->bo.offset }; | 510 | new_bo->bo.offset }; |
501 | 511 | ||
502 | /* Choose the channel the flip will be handled in */ | 512 | /* Choose the channel the flip will be handled in */ |
503 | chan = nouveau_fence_channel(new_bo->bo.sync_obj); | 513 | fence = new_bo->bo.sync_obj; |
514 | if (fence) | ||
515 | chan = nouveau_channel_get_unlocked(fence->channel); | ||
504 | if (!chan) | 516 | if (!chan) |
505 | chan = nouveau_channel_get_unlocked(dev_priv->channel); | 517 | chan = nouveau_channel_get_unlocked(dev_priv->channel); |
506 | mutex_lock(&chan->mutex); | 518 | mutex_lock(&chan->mutex); |
@@ -540,20 +552,20 @@ int | |||
540 | nouveau_finish_page_flip(struct nouveau_channel *chan, | 552 | nouveau_finish_page_flip(struct nouveau_channel *chan, |
541 | struct nouveau_page_flip_state *ps) | 553 | struct nouveau_page_flip_state *ps) |
542 | { | 554 | { |
555 | struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW]; | ||
543 | struct drm_device *dev = chan->dev; | 556 | struct drm_device *dev = chan->dev; |
544 | struct nouveau_page_flip_state *s; | 557 | struct nouveau_page_flip_state *s; |
545 | unsigned long flags; | 558 | unsigned long flags; |
546 | 559 | ||
547 | spin_lock_irqsave(&dev->event_lock, flags); | 560 | spin_lock_irqsave(&dev->event_lock, flags); |
548 | 561 | ||
549 | if (list_empty(&chan->nvsw.flip)) { | 562 | if (list_empty(&swch->flip)) { |
550 | NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id); | 563 | NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id); |
551 | spin_unlock_irqrestore(&dev->event_lock, flags); | 564 | spin_unlock_irqrestore(&dev->event_lock, flags); |
552 | return -EINVAL; | 565 | return -EINVAL; |
553 | } | 566 | } |
554 | 567 | ||
555 | s = list_first_entry(&chan->nvsw.flip, | 568 | s = list_first_entry(&swch->flip, struct nouveau_page_flip_state, head); |
556 | struct nouveau_page_flip_state, head); | ||
557 | if (s->event) { | 569 | if (s->event) { |
558 | struct drm_pending_vblank_event *e = s->event; | 570 | struct drm_pending_vblank_event *e = s->event; |
559 | struct timeval now; | 571 | struct timeval now; |