Backmerge remote-tracking branch 'drm/drm-next' into drm-misc-next
[linux-block.git] / drivers / gpu / drm / nouveau / dispnv50 / wndw.c
index ee0fd817185e2ebb2d014aa9fee009b5d84996fe..720fe75de1859b2fc7cc901bb5af7fee3d6fbabe 100644 (file)
@@ -29,6 +29,7 @@
 #include <drm/drm_fourcc.h>
 
 #include "nouveau_bo.h"
+#include "nouveau_gem.h"
 
 static void
 nv50_wndw_ctxdma_del(struct nv50_wndw_ctxdma *ctxdma)
@@ -39,12 +40,13 @@ nv50_wndw_ctxdma_del(struct nv50_wndw_ctxdma *ctxdma)
 }
 
 static struct nv50_wndw_ctxdma *
-nv50_wndw_ctxdma_new(struct nv50_wndw *wndw, struct nouveau_framebuffer *fb)
+nv50_wndw_ctxdma_new(struct nv50_wndw *wndw, struct drm_framebuffer *fb)
 {
-       struct nouveau_drm *drm = nouveau_drm(fb->base.dev);
+       struct nouveau_drm *drm = nouveau_drm(fb->dev);
        struct nv50_wndw_ctxdma *ctxdma;
-       const u8    kind = fb->nvbo->kind;
-       const u32 handle = 0xfb000000 | kind;
+       u32 handle;
+       u32 unused;
+       u8  kind;
        struct {
                struct nv_dma_v0 base;
                union {
@@ -56,6 +58,9 @@ nv50_wndw_ctxdma_new(struct nv50_wndw *wndw, struct nouveau_framebuffer *fb)
        u32 argc = sizeof(args.base);
        int ret;
 
+       nouveau_framebuffer_get_layout(fb, &unused, &kind);
+       handle = 0xfb000000 | kind;
+
        list_for_each_entry(ctxdma, &wndw->ctxdma.list, head) {
                if (ctxdma->object.handle == handle)
                        return ctxdma;
@@ -187,6 +192,8 @@ nv50_wndw_atomic_check_release(struct nv50_wndw *wndw,
        wndw->func->release(wndw, asyw, asyh);
        asyw->ntfy.handle = 0;
        asyw->sema.handle = 0;
+       asyw->xlut.handle = 0;
+       memset(asyw->image.handle, 0x00, sizeof(asyw->image.handle));
 }
 
 static int
@@ -234,16 +241,20 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, bool modeset,
                               struct nv50_wndw_atom *asyw,
                               struct nv50_head_atom *asyh)
 {
-       struct nouveau_framebuffer *fb = nouveau_framebuffer(asyw->state.fb);
+       struct drm_framebuffer *fb = asyw->state.fb;
        struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
+       uint8_t kind;
+       uint32_t tile_mode;
        int ret;
 
        NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name);
 
-       if (asyw->state.fb != armw->state.fb || !armw->visible || modeset) {
-               asyw->image.w = fb->base.width;
-               asyw->image.h = fb->base.height;
-               asyw->image.kind = fb->nvbo->kind;
+       if (fb != armw->state.fb || !armw->visible || modeset) {
+               nouveau_framebuffer_get_layout(fb, &tile_mode, &kind);
+
+               asyw->image.w = fb->width;
+               asyw->image.h = fb->height;
+               asyw->image.kind = kind;
 
                ret = nv50_wndw_atomic_check_acquire_rgb(asyw);
                if (ret) {
@@ -255,16 +266,16 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, bool modeset,
                if (asyw->image.kind) {
                        asyw->image.layout = 0;
                        if (drm->client.device.info.chipset >= 0xc0)
-                               asyw->image.blockh = fb->nvbo->mode >> 4;
+                               asyw->image.blockh = tile_mode >> 4;
                        else
-                               asyw->image.blockh = fb->nvbo->mode;
-                       asyw->image.blocks[0] = fb->base.pitches[0] / 64;
+                               asyw->image.blockh = tile_mode;
+                       asyw->image.blocks[0] = fb->pitches[0] / 64;
                        asyw->image.pitch[0] = 0;
                } else {
                        asyw->image.layout = 1;
                        asyw->image.blockh = 0;
                        asyw->image.blocks[0] = 0;
-                       asyw->image.pitch[0] = fb->base.pitches[0];
+                       asyw->image.pitch[0] = fb->pitches[0];
                }
 
                if (!asyh->state.async_flip)
@@ -471,47 +482,51 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
 static void
 nv50_wndw_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state)
 {
-       struct nouveau_framebuffer *fb = nouveau_framebuffer(old_state->fb);
        struct nouveau_drm *drm = nouveau_drm(plane->dev);
+       struct nouveau_bo *nvbo;
 
        NV_ATOMIC(drm, "%s cleanup: %p\n", plane->name, old_state->fb);
        if (!old_state->fb)
                return;
 
-       nouveau_bo_unpin(fb->nvbo);
+       nvbo = nouveau_gem_object(old_state->fb->obj[0]);
+       nouveau_bo_unpin(nvbo);
 }
 
 static int
 nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
 {
-       struct nouveau_framebuffer *fb = nouveau_framebuffer(state->fb);
+       struct drm_framebuffer *fb = state->fb;
        struct nouveau_drm *drm = nouveau_drm(plane->dev);
        struct nv50_wndw *wndw = nv50_wndw(plane);
        struct nv50_wndw_atom *asyw = nv50_wndw_atom(state);
+       struct nouveau_bo *nvbo;
        struct nv50_head_atom *asyh;
        struct nv50_wndw_ctxdma *ctxdma;
        int ret;
 
-       NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, state->fb);
+       NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, fb);
        if (!asyw->state.fb)
                return 0;
 
-       ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM, true);
+       nvbo = nouveau_gem_object(fb->obj[0]);
+       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
        if (ret)
                return ret;
 
        if (wndw->ctxdma.parent) {
                ctxdma = nv50_wndw_ctxdma_new(wndw, fb);
                if (IS_ERR(ctxdma)) {
-                       nouveau_bo_unpin(fb->nvbo);
+                       nouveau_bo_unpin(nvbo);
                        return PTR_ERR(ctxdma);
                }
 
-               asyw->image.handle[0] = ctxdma->object.handle;
+               if (asyw->visible)
+                       asyw->image.handle[0] = ctxdma->object.handle;
        }
 
-       asyw->state.fence = dma_resv_get_excl_rcu(fb->nvbo->bo.base.resv);
-       asyw->image.offset[0] = fb->nvbo->offset;
+       asyw->state.fence = dma_resv_get_excl_rcu(nvbo->bo.base.resv);
+       asyw->image.offset[0] = nvbo->offset;
 
        if (wndw->func->prepare) {
                asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc);
@@ -603,6 +618,29 @@ nv50_wndw_destroy(struct drm_plane *plane)
        kfree(wndw);
 }
 
+/* This function assumes the format has already been validated against the plane
+ * and the modifier was validated against the device-wides modifier list at FB
+ * creation time.
+ */
+static bool nv50_plane_format_mod_supported(struct drm_plane *plane,
+                                           u32 format, u64 modifier)
+{
+       struct nouveau_drm *drm = nouveau_drm(plane->dev);
+       uint8_t i;
+
+       if (drm->client.device.info.chipset < 0xc0) {
+               const struct drm_format_info *info = drm_format_info(format);
+               const uint8_t kind = (modifier >> 12) & 0xff;
+
+               if (!format) return false;
+
+               for (i = 0; i < info->num_planes; i++)
+                       if ((info->cpp[i] != 4) && kind != 0x70) return false;
+       }
+
+       return true;
+}
+
 const struct drm_plane_funcs
 nv50_wndw = {
        .update_plane = drm_atomic_helper_update_plane,
@@ -611,6 +649,7 @@ nv50_wndw = {
        .reset = nv50_wndw_reset,
        .atomic_duplicate_state = nv50_wndw_atomic_duplicate_state,
        .atomic_destroy_state = nv50_wndw_atomic_destroy_state,
+       .format_mod_supported = nv50_plane_format_mod_supported,
 };
 
 static int
@@ -658,7 +697,8 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
        for (nformat = 0; format[nformat]; nformat++);
 
        ret = drm_universal_plane_init(dev, &wndw->plane, heads, &nv50_wndw,
-                                      format, nformat, NULL,
+                                      format, nformat,
+                                      nouveau_display(dev)->format_modifiers,
                                       type, "%s-%d", name, index);
        if (ret) {
                kfree(*pwndw);