Loading drivers/gpu/drm/nouveau/dispnv04/crtc.c +213 −1 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "nvreg.h" #include "nouveau_fbcon.h" #include "disp.h" #include "nouveau_dma.h" #include <subdev/bios/pll.h> #include <subdev/clk.h> Loading Loading @@ -1077,12 +1078,223 @@ nouveau_crtc_set_config(struct drm_mode_set *set, return ret; } struct nv04_page_flip_state { struct list_head head; struct drm_pending_vblank_event *event; struct drm_crtc *crtc; int bpp, pitch; u64 offset; }; static int nv04_finish_page_flip(struct nouveau_channel *chan, struct nv04_page_flip_state *ps) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; struct nv04_page_flip_state *s; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); if (list_empty(&fctx->flip)) { NV_ERROR(drm, "unexpected pageflip\n"); spin_unlock_irqrestore(&dev->event_lock, flags); return -EINVAL; } s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head); if (s->event) { drm_crtc_arm_vblank_event(s->crtc, s->event); } else { /* Give up ownership of vblank for page-flipped crtc */ drm_crtc_vblank_put(s->crtc); } list_del(&s->head); if (ps) *ps = *s; kfree(s); spin_unlock_irqrestore(&dev->event_lock, flags); return 0; } int nv04_flip_complete(struct nvif_notify *notify) { struct nouveau_cli *cli = (void *)notify->object->client; struct nouveau_drm *drm = cli->drm; struct nouveau_channel *chan = drm->channel; struct nv04_page_flip_state state; if (!nv04_finish_page_flip(chan, &state)) { nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), state.offset + state.crtc->y * state.pitch + state.crtc->x * state.bpp / 8); } return NVIF_NOTIFY_KEEP; } static int nv04_page_flip_emit(struct nouveau_channel *chan, struct nouveau_bo *old_bo, struct nouveau_bo *new_bo, struct nv04_page_flip_state *s, struct nouveau_fence **pfence) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; unsigned long flags; int ret; /* Queue it to the pending list */ spin_lock_irqsave(&dev->event_lock, flags); list_add_tail(&s->head, &fctx->flip); spin_unlock_irqrestore(&dev->event_lock, flags); /* Synchronize with the old framebuffer */ ret = nouveau_fence_sync(old_bo, chan, false, false); if (ret) goto fail; /* Emit the pageflip */ ret = RING_SPACE(chan, 2); if (ret) goto fail; BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); OUT_RING (chan, 0x00000000); FIRE_RING (chan); ret = nouveau_fence_new(chan, false, pfence); if (ret) goto fail; return 0; fail: spin_lock_irqsave(&dev->event_lock, flags); list_del(&s->head); spin_unlock_irqrestore(&dev->event_lock, flags); return ret; } static int nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, u32 flags, struct drm_modeset_acquire_ctx *ctx) { const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nv04_page_flip_state *s; struct nouveau_channel *chan; struct nouveau_cli *cli; struct nouveau_fence *fence; struct nv04_display *dispnv04 = nv04_display(dev); int head = nouveau_crtc(crtc)->index; int ret; chan = drm->channel; if (!chan) return -ENODEV; cli = (void *)chan->user.client; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM; if (new_bo != old_bo) { ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true); if (ret) goto fail_free; } mutex_lock(&cli->mutex); ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); if (ret) goto fail_unpin; /* synchronise rendering channel with the kernel's channel */ ret = nouveau_fence_sync(new_bo, chan, false, true); if (ret) { ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; } if (new_bo != old_bo) { ttm_bo_unreserve(&new_bo->bo); ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); if (ret) goto fail_unpin; } /* Initialize a page flip struct */ *s = (struct nv04_page_flip_state) { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], new_bo->bo.offset }; /* Keep vblanks on during flip, for the target crtc of this flip */ drm_crtc_vblank_get(crtc); /* Emit a page flip */ if (swap_interval) { ret = RING_SPACE(chan, 8); if (ret) goto fail_unreserve; BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); OUT_RING (chan, head); BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); OUT_RING (chan, 0); } nouveau_bo_ref(new_bo, &dispnv04->image[head]); ret = nv04_page_flip_emit(chan, old_bo, new_bo, s, &fence); if (ret) goto fail_unreserve; mutex_unlock(&cli->mutex); /* Update the crtc struct and cleanup */ crtc->primary->fb = fb; nouveau_bo_fence(old_bo, fence, false); ttm_bo_unreserve(&old_bo->bo); if (old_bo != new_bo) nouveau_bo_unpin(old_bo); nouveau_fence_unref(&fence); return 0; fail_unreserve: drm_crtc_vblank_put(crtc); ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&cli->mutex); if (old_bo != new_bo) nouveau_bo_unpin(new_bo); fail_free: kfree(s); return ret; } static const struct drm_crtc_funcs nv04_crtc_funcs = { .cursor_set = nv04_crtc_cursor_set, .cursor_move = nv04_crtc_cursor_move, .gamma_set = nv_crtc_gamma_set, .set_config = nouveau_crtc_set_config, .page_flip = nouveau_crtc_page_flip, .page_flip = nv04_crtc_page_flip, .destroy = nv_crtc_destroy, }; Loading drivers/gpu/drm/nouveau/dispnv04/disp.c +19 −0 Original line number Diff line number Diff line Loading @@ -31,9 +31,16 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" #include <nvif/if0004.h> static void nv04_display_fini(struct drm_device *dev) { struct nv04_display *disp = nv04_display(dev); /* Disable flip completion events. */ nvif_notify_put(&disp->flip); /* Disable vblank interrupts. */ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0); if (nv_two_heads(dev)) Loading @@ -43,6 +50,7 @@ nv04_display_fini(struct drm_device *dev) static int nv04_display_init(struct drm_device *dev) { struct nv04_display *disp = nv04_display(dev); struct nouveau_encoder *encoder; struct nouveau_crtc *crtc; Loading @@ -60,6 +68,8 @@ nv04_display_init(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head) encoder->enc_save(&encoder->base.base); /* Enable flip completion events. */ nvif_notify_get(&disp->flip); return 0; } Loading @@ -80,6 +90,8 @@ nv04_display_destroy(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 0); nvif_notify_fini(&disp->flip); nouveau_display(dev)->priv = NULL; kfree(disp); Loading Loading @@ -113,6 +125,13 @@ nv04_display_create(struct drm_device *dev) /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */ dev->driver->driver_features &= ~DRIVER_ATOMIC; /* Request page flip completion event. */ if (drm->nvsw.client) { nvif_notify_init(&drm->nvsw, nv04_flip_complete, false, NV04_NVSW_NTFY_UEVENT, NULL, 0, 0, &disp->flip); } nouveau_hw_save_vga_fonts(dev, 1); nv04_crtc_create(dev, 0); Loading drivers/gpu/drm/nouveau/dispnv04/disp.h +2 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ struct nv04_display { uint32_t saved_vga_font[4][16384]; uint32_t dac_users[4]; struct nouveau_bo *image[2]; struct nvif_notify flip; }; static inline struct nv04_display * Loading Loading @@ -173,4 +174,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table, ); } int nv04_flip_complete(struct nvif_notify *); #endif drivers/gpu/drm/nouveau/nouveau_display.c +1 −214 Original line number Diff line number Diff line Loading @@ -32,18 +32,13 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_probe_helper.h> #include <nvif/class.h> #include "nouveau_fbcon.h" #include "dispnv04/hw.h" #include "nouveau_crtc.h" #include "nouveau_dma.h" #include "nouveau_gem.h" #include "nouveau_connector.h" #include "nv50_display.h" #include "nouveau_fence.h" #include <nvif/class.h> #include <nvif/cl0046.h> #include <nvif/event.h> Loading Loading @@ -415,7 +410,6 @@ int nouveau_display_init(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; struct drm_connector_list_iter conn_iter; int ret; Loading @@ -437,8 +431,6 @@ nouveau_display_init(struct drm_device *dev) } drm_connector_list_iter_end(&conn_iter); /* enable flip completion events */ nvif_notify_get(&drm->flip); return ret; } Loading @@ -457,9 +449,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) drm_helper_force_disable_all(dev); } /* disable flip completion events */ nvif_notify_put(&drm->flip); /* disable hotplug interrupts */ drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { Loading Loading @@ -738,208 +727,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) } } static int nouveau_page_flip_emit(struct nouveau_channel *chan, struct nouveau_bo *old_bo, struct nouveau_bo *new_bo, struct nouveau_page_flip_state *s, struct nouveau_fence **pfence) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; unsigned long flags; int ret; /* Queue it to the pending list */ spin_lock_irqsave(&dev->event_lock, flags); list_add_tail(&s->head, &fctx->flip); spin_unlock_irqrestore(&dev->event_lock, flags); /* Synchronize with the old framebuffer */ ret = nouveau_fence_sync(old_bo, chan, false, false); if (ret) goto fail; /* Emit the pageflip */ ret = RING_SPACE(chan, 2); if (ret) goto fail; BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); OUT_RING (chan, 0x00000000); FIRE_RING (chan); ret = nouveau_fence_new(chan, false, pfence); if (ret) goto fail; return 0; fail: spin_lock_irqsave(&dev->event_lock, flags); list_del(&s->head); spin_unlock_irqrestore(&dev->event_lock, flags); return ret; } int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, u32 flags, struct drm_modeset_acquire_ctx *ctx) { const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nouveau_page_flip_state *s; struct nouveau_channel *chan; struct nouveau_cli *cli; struct nouveau_fence *fence; struct nv04_display *dispnv04 = nv04_display(dev); int head = nouveau_crtc(crtc)->index; int ret; chan = drm->channel; if (!chan) return -ENODEV; cli = (void *)chan->user.client; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM; if (new_bo != old_bo) { ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true); if (ret) goto fail_free; } mutex_lock(&cli->mutex); ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); if (ret) goto fail_unpin; /* synchronise rendering channel with the kernel's channel */ ret = nouveau_fence_sync(new_bo, chan, false, true); if (ret) { ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; } if (new_bo != old_bo) { ttm_bo_unreserve(&new_bo->bo); ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); if (ret) goto fail_unpin; } /* Initialize a page flip struct */ *s = (struct nouveau_page_flip_state) { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], new_bo->bo.offset }; /* Keep vblanks on during flip, for the target crtc of this flip */ drm_crtc_vblank_get(crtc); /* Emit a page flip */ if (swap_interval) { ret = RING_SPACE(chan, 8); if (ret) goto fail_unreserve; BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); OUT_RING (chan, head); BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); OUT_RING (chan, 0); } nouveau_bo_ref(new_bo, &dispnv04->image[head]); ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); if (ret) goto fail_unreserve; mutex_unlock(&cli->mutex); /* Update the crtc struct and cleanup */ crtc->primary->fb = fb; nouveau_bo_fence(old_bo, fence, false); ttm_bo_unreserve(&old_bo->bo); if (old_bo != new_bo) nouveau_bo_unpin(old_bo); nouveau_fence_unref(&fence); return 0; fail_unreserve: drm_crtc_vblank_put(crtc); ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&cli->mutex); if (old_bo != new_bo) nouveau_bo_unpin(new_bo); fail_free: kfree(s); return ret; } int nouveau_finish_page_flip(struct nouveau_channel *chan, struct nouveau_page_flip_state *ps) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; struct nouveau_page_flip_state *s; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); if (list_empty(&fctx->flip)) { NV_ERROR(drm, "unexpected pageflip\n"); spin_unlock_irqrestore(&dev->event_lock, flags); return -EINVAL; } s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { drm_crtc_arm_vblank_event(s->crtc, s->event); } else { /* Give up ownership of vblank for page-flipped crtc */ drm_crtc_vblank_put(s->crtc); } list_del(&s->head); if (ps) *ps = *s; kfree(s); spin_unlock_irqrestore(&dev->event_lock, flags); return 0; } int nouveau_flip_complete(struct nvif_notify *notify) { struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip); struct nouveau_channel *chan = drm->channel; struct nouveau_page_flip_state state; if (!nouveau_finish_page_flip(chan, &state)) { nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), state.offset + state.crtc->y * state.pitch + state.crtc->x * state.bpp / 8); } return NVIF_NOTIFY_KEEP; } int nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) Loading drivers/gpu/drm/nouveau/nouveau_display.h +0 −15 Original line number Diff line number Diff line Loading @@ -25,14 +25,6 @@ int nouveau_framebuffer_new(struct drm_device *, const struct drm_mode_fb_cmd2 *, struct nouveau_bo *, struct nouveau_framebuffer **); struct nouveau_page_flip_state { struct list_head head; struct drm_pending_vblank_event *event; struct drm_crtc *crtc; int bpp, pitch; u64 offset; }; struct nouveau_display { void *priv; void (*dtor)(struct drm_device *); Loading Loading @@ -71,13 +63,6 @@ bool nouveau_display_scanoutpos(struct drm_device *, unsigned int, bool, int *, int *, ktime_t *, ktime_t *, const struct drm_display_mode *); int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx); int nouveau_finish_page_flip(struct nouveau_channel *, struct nouveau_page_flip_state *); int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, struct drm_mode_create_dumb *args); int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, Loading Loading
drivers/gpu/drm/nouveau/dispnv04/crtc.c +213 −1 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "nvreg.h" #include "nouveau_fbcon.h" #include "disp.h" #include "nouveau_dma.h" #include <subdev/bios/pll.h> #include <subdev/clk.h> Loading Loading @@ -1077,12 +1078,223 @@ nouveau_crtc_set_config(struct drm_mode_set *set, return ret; } struct nv04_page_flip_state { struct list_head head; struct drm_pending_vblank_event *event; struct drm_crtc *crtc; int bpp, pitch; u64 offset; }; static int nv04_finish_page_flip(struct nouveau_channel *chan, struct nv04_page_flip_state *ps) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; struct nv04_page_flip_state *s; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); if (list_empty(&fctx->flip)) { NV_ERROR(drm, "unexpected pageflip\n"); spin_unlock_irqrestore(&dev->event_lock, flags); return -EINVAL; } s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head); if (s->event) { drm_crtc_arm_vblank_event(s->crtc, s->event); } else { /* Give up ownership of vblank for page-flipped crtc */ drm_crtc_vblank_put(s->crtc); } list_del(&s->head); if (ps) *ps = *s; kfree(s); spin_unlock_irqrestore(&dev->event_lock, flags); return 0; } int nv04_flip_complete(struct nvif_notify *notify) { struct nouveau_cli *cli = (void *)notify->object->client; struct nouveau_drm *drm = cli->drm; struct nouveau_channel *chan = drm->channel; struct nv04_page_flip_state state; if (!nv04_finish_page_flip(chan, &state)) { nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), state.offset + state.crtc->y * state.pitch + state.crtc->x * state.bpp / 8); } return NVIF_NOTIFY_KEEP; } static int nv04_page_flip_emit(struct nouveau_channel *chan, struct nouveau_bo *old_bo, struct nouveau_bo *new_bo, struct nv04_page_flip_state *s, struct nouveau_fence **pfence) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; unsigned long flags; int ret; /* Queue it to the pending list */ spin_lock_irqsave(&dev->event_lock, flags); list_add_tail(&s->head, &fctx->flip); spin_unlock_irqrestore(&dev->event_lock, flags); /* Synchronize with the old framebuffer */ ret = nouveau_fence_sync(old_bo, chan, false, false); if (ret) goto fail; /* Emit the pageflip */ ret = RING_SPACE(chan, 2); if (ret) goto fail; BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); OUT_RING (chan, 0x00000000); FIRE_RING (chan); ret = nouveau_fence_new(chan, false, pfence); if (ret) goto fail; return 0; fail: spin_lock_irqsave(&dev->event_lock, flags); list_del(&s->head); spin_unlock_irqrestore(&dev->event_lock, flags); return ret; } static int nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, u32 flags, struct drm_modeset_acquire_ctx *ctx) { const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nv04_page_flip_state *s; struct nouveau_channel *chan; struct nouveau_cli *cli; struct nouveau_fence *fence; struct nv04_display *dispnv04 = nv04_display(dev); int head = nouveau_crtc(crtc)->index; int ret; chan = drm->channel; if (!chan) return -ENODEV; cli = (void *)chan->user.client; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM; if (new_bo != old_bo) { ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true); if (ret) goto fail_free; } mutex_lock(&cli->mutex); ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); if (ret) goto fail_unpin; /* synchronise rendering channel with the kernel's channel */ ret = nouveau_fence_sync(new_bo, chan, false, true); if (ret) { ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; } if (new_bo != old_bo) { ttm_bo_unreserve(&new_bo->bo); ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); if (ret) goto fail_unpin; } /* Initialize a page flip struct */ *s = (struct nv04_page_flip_state) { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], new_bo->bo.offset }; /* Keep vblanks on during flip, for the target crtc of this flip */ drm_crtc_vblank_get(crtc); /* Emit a page flip */ if (swap_interval) { ret = RING_SPACE(chan, 8); if (ret) goto fail_unreserve; BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); OUT_RING (chan, head); BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); OUT_RING (chan, 0); } nouveau_bo_ref(new_bo, &dispnv04->image[head]); ret = nv04_page_flip_emit(chan, old_bo, new_bo, s, &fence); if (ret) goto fail_unreserve; mutex_unlock(&cli->mutex); /* Update the crtc struct and cleanup */ crtc->primary->fb = fb; nouveau_bo_fence(old_bo, fence, false); ttm_bo_unreserve(&old_bo->bo); if (old_bo != new_bo) nouveau_bo_unpin(old_bo); nouveau_fence_unref(&fence); return 0; fail_unreserve: drm_crtc_vblank_put(crtc); ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&cli->mutex); if (old_bo != new_bo) nouveau_bo_unpin(new_bo); fail_free: kfree(s); return ret; } static const struct drm_crtc_funcs nv04_crtc_funcs = { .cursor_set = nv04_crtc_cursor_set, .cursor_move = nv04_crtc_cursor_move, .gamma_set = nv_crtc_gamma_set, .set_config = nouveau_crtc_set_config, .page_flip = nouveau_crtc_page_flip, .page_flip = nv04_crtc_page_flip, .destroy = nv_crtc_destroy, }; Loading
drivers/gpu/drm/nouveau/dispnv04/disp.c +19 −0 Original line number Diff line number Diff line Loading @@ -31,9 +31,16 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" #include <nvif/if0004.h> static void nv04_display_fini(struct drm_device *dev) { struct nv04_display *disp = nv04_display(dev); /* Disable flip completion events. */ nvif_notify_put(&disp->flip); /* Disable vblank interrupts. */ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0); if (nv_two_heads(dev)) Loading @@ -43,6 +50,7 @@ nv04_display_fini(struct drm_device *dev) static int nv04_display_init(struct drm_device *dev) { struct nv04_display *disp = nv04_display(dev); struct nouveau_encoder *encoder; struct nouveau_crtc *crtc; Loading @@ -60,6 +68,8 @@ nv04_display_init(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head) encoder->enc_save(&encoder->base.base); /* Enable flip completion events. */ nvif_notify_get(&disp->flip); return 0; } Loading @@ -80,6 +90,8 @@ nv04_display_destroy(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 0); nvif_notify_fini(&disp->flip); nouveau_display(dev)->priv = NULL; kfree(disp); Loading Loading @@ -113,6 +125,13 @@ nv04_display_create(struct drm_device *dev) /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */ dev->driver->driver_features &= ~DRIVER_ATOMIC; /* Request page flip completion event. */ if (drm->nvsw.client) { nvif_notify_init(&drm->nvsw, nv04_flip_complete, false, NV04_NVSW_NTFY_UEVENT, NULL, 0, 0, &disp->flip); } nouveau_hw_save_vga_fonts(dev, 1); nv04_crtc_create(dev, 0); Loading
drivers/gpu/drm/nouveau/dispnv04/disp.h +2 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ struct nv04_display { uint32_t saved_vga_font[4][16384]; uint32_t dac_users[4]; struct nouveau_bo *image[2]; struct nvif_notify flip; }; static inline struct nv04_display * Loading Loading @@ -173,4 +174,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table, ); } int nv04_flip_complete(struct nvif_notify *); #endif
drivers/gpu/drm/nouveau/nouveau_display.c +1 −214 Original line number Diff line number Diff line Loading @@ -32,18 +32,13 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_probe_helper.h> #include <nvif/class.h> #include "nouveau_fbcon.h" #include "dispnv04/hw.h" #include "nouveau_crtc.h" #include "nouveau_dma.h" #include "nouveau_gem.h" #include "nouveau_connector.h" #include "nv50_display.h" #include "nouveau_fence.h" #include <nvif/class.h> #include <nvif/cl0046.h> #include <nvif/event.h> Loading Loading @@ -415,7 +410,6 @@ int nouveau_display_init(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; struct drm_connector_list_iter conn_iter; int ret; Loading @@ -437,8 +431,6 @@ nouveau_display_init(struct drm_device *dev) } drm_connector_list_iter_end(&conn_iter); /* enable flip completion events */ nvif_notify_get(&drm->flip); return ret; } Loading @@ -457,9 +449,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) drm_helper_force_disable_all(dev); } /* disable flip completion events */ nvif_notify_put(&drm->flip); /* disable hotplug interrupts */ drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { Loading Loading @@ -738,208 +727,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) } } static int nouveau_page_flip_emit(struct nouveau_channel *chan, struct nouveau_bo *old_bo, struct nouveau_bo *new_bo, struct nouveau_page_flip_state *s, struct nouveau_fence **pfence) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; unsigned long flags; int ret; /* Queue it to the pending list */ spin_lock_irqsave(&dev->event_lock, flags); list_add_tail(&s->head, &fctx->flip); spin_unlock_irqrestore(&dev->event_lock, flags); /* Synchronize with the old framebuffer */ ret = nouveau_fence_sync(old_bo, chan, false, false); if (ret) goto fail; /* Emit the pageflip */ ret = RING_SPACE(chan, 2); if (ret) goto fail; BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); OUT_RING (chan, 0x00000000); FIRE_RING (chan); ret = nouveau_fence_new(chan, false, pfence); if (ret) goto fail; return 0; fail: spin_lock_irqsave(&dev->event_lock, flags); list_del(&s->head); spin_unlock_irqrestore(&dev->event_lock, flags); return ret; } int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, u32 flags, struct drm_modeset_acquire_ctx *ctx) { const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nouveau_page_flip_state *s; struct nouveau_channel *chan; struct nouveau_cli *cli; struct nouveau_fence *fence; struct nv04_display *dispnv04 = nv04_display(dev); int head = nouveau_crtc(crtc)->index; int ret; chan = drm->channel; if (!chan) return -ENODEV; cli = (void *)chan->user.client; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM; if (new_bo != old_bo) { ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true); if (ret) goto fail_free; } mutex_lock(&cli->mutex); ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); if (ret) goto fail_unpin; /* synchronise rendering channel with the kernel's channel */ ret = nouveau_fence_sync(new_bo, chan, false, true); if (ret) { ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; } if (new_bo != old_bo) { ttm_bo_unreserve(&new_bo->bo); ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); if (ret) goto fail_unpin; } /* Initialize a page flip struct */ *s = (struct nouveau_page_flip_state) { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], new_bo->bo.offset }; /* Keep vblanks on during flip, for the target crtc of this flip */ drm_crtc_vblank_get(crtc); /* Emit a page flip */ if (swap_interval) { ret = RING_SPACE(chan, 8); if (ret) goto fail_unreserve; BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); OUT_RING (chan, head); BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); OUT_RING (chan, 0); BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); OUT_RING (chan, 0); } nouveau_bo_ref(new_bo, &dispnv04->image[head]); ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); if (ret) goto fail_unreserve; mutex_unlock(&cli->mutex); /* Update the crtc struct and cleanup */ crtc->primary->fb = fb; nouveau_bo_fence(old_bo, fence, false); ttm_bo_unreserve(&old_bo->bo); if (old_bo != new_bo) nouveau_bo_unpin(old_bo); nouveau_fence_unref(&fence); return 0; fail_unreserve: drm_crtc_vblank_put(crtc); ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&cli->mutex); if (old_bo != new_bo) nouveau_bo_unpin(new_bo); fail_free: kfree(s); return ret; } int nouveau_finish_page_flip(struct nouveau_channel *chan, struct nouveau_page_flip_state *ps) { struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_drm *drm = chan->drm; struct drm_device *dev = drm->dev; struct nouveau_page_flip_state *s; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); if (list_empty(&fctx->flip)) { NV_ERROR(drm, "unexpected pageflip\n"); spin_unlock_irqrestore(&dev->event_lock, flags); return -EINVAL; } s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { drm_crtc_arm_vblank_event(s->crtc, s->event); } else { /* Give up ownership of vblank for page-flipped crtc */ drm_crtc_vblank_put(s->crtc); } list_del(&s->head); if (ps) *ps = *s; kfree(s); spin_unlock_irqrestore(&dev->event_lock, flags); return 0; } int nouveau_flip_complete(struct nvif_notify *notify) { struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip); struct nouveau_channel *chan = drm->channel; struct nouveau_page_flip_state state; if (!nouveau_finish_page_flip(chan, &state)) { nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), state.offset + state.crtc->y * state.pitch + state.crtc->x * state.bpp / 8); } return NVIF_NOTIFY_KEEP; } int nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) Loading
drivers/gpu/drm/nouveau/nouveau_display.h +0 −15 Original line number Diff line number Diff line Loading @@ -25,14 +25,6 @@ int nouveau_framebuffer_new(struct drm_device *, const struct drm_mode_fb_cmd2 *, struct nouveau_bo *, struct nouveau_framebuffer **); struct nouveau_page_flip_state { struct list_head head; struct drm_pending_vblank_event *event; struct drm_crtc *crtc; int bpp, pitch; u64 offset; }; struct nouveau_display { void *priv; void (*dtor)(struct drm_device *); Loading Loading @@ -71,13 +63,6 @@ bool nouveau_display_scanoutpos(struct drm_device *, unsigned int, bool, int *, int *, ktime_t *, ktime_t *, const struct drm_display_mode *); int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx); int nouveau_finish_page_flip(struct nouveau_channel *, struct nouveau_page_flip_state *); int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, struct drm_mode_create_dumb *args); int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, Loading