Commit 2ce7f386 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/kms/nv50-: initial overlay support

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 88b600d4
......@@ -40,3 +40,4 @@ nouveau-y += dispnv50/ovly.o
nouveau-y += dispnv50/ovly507e.o
nouveau-y += dispnv50/ovly827e.o
nouveau-y += dispnv50/ovly907e.o
nouveau-y += dispnv50/ovly917e.o
......@@ -173,6 +173,7 @@ struct nv50_wndw_atom {
u8 mode:2;
u8 interval:4;
u8 colorspace:2;
u8 format;
u8 kind:7;
u8 layout:1;
......@@ -186,6 +187,15 @@ struct nv50_wndw_atom {
u64 offset[6];
} image;
struct {
u16 sx;
u16 sy;
u16 sw;
u16 sh;
u16 dw;
u16 dh;
} scale;
struct {
u16 x;
u16 y;
......@@ -197,6 +207,7 @@ struct nv50_wndw_atom {
bool sema:1;
bool xlut:1;
bool image:1;
bool scale:1;
bool point:1;
};
u8 mask;
......
......@@ -13,10 +13,8 @@ void base507c_release(struct nv50_wndw *, struct nv50_wndw_atom *,
struct nv50_head_atom *);
void base507c_sema_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void base507c_sema_clr(struct nv50_wndw *);
void base507c_ntfy_reset(struct nouveau_bo *, u32);
void base507c_ntfy_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void base507c_ntfy_clr(struct nv50_wndw *);
int base507c_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
void base507c_xlut_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void base507c_xlut_clr(struct nv50_wndw *);
void base507c_image_clr(struct nv50_wndw *);
......
......@@ -6,7 +6,6 @@ int curs507a_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int curs507a_new_(const struct nv50_wimm_func *, struct nouveau_drm *,
int head, s32 oclass, u32 interlock_data,
struct nv50_wndw **);
extern const struct nv50_wimm_func curs507a;
int curs907a_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
......
......@@ -16,6 +16,9 @@ struct nv50_disp {
#define NV50_DISP_BASE_SEM0(c) NV50_DISP_WNDW_SEM0(0 + (c))
#define NV50_DISP_BASE_SEM1(c) NV50_DISP_WNDW_SEM1(0 + (c))
#define NV50_DISP_BASE_NTFY(c) NV50_DISP_WNDW_NTFY(0 + (c))
#define NV50_DISP_OVLY_SEM0(c) NV50_DISP_WNDW_SEM0(4 + (c))
#define NV50_DISP_OVLY_SEM1(c) NV50_DISP_WNDW_SEM1(4 + (c))
#define NV50_DISP_OVLY_NTFY(c) NV50_DISP_WNDW_NTFY(4 + (c))
struct nouveau_bo *sync;
struct mutex mutex;
......
......@@ -58,7 +58,6 @@ head507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
if (asyh->ovly.cpp) {
switch (asyh->ovly.cpp) {
case 8: bounds |= 0x00000500; break;
case 4: bounds |= 0x00000300; break;
case 2: bounds |= 0x00000100; break;
default:
......@@ -66,6 +65,8 @@ head507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
break;
}
bounds |= 0x00000001;
} else {
bounds |= 0x00000100;
}
if ((push = evo_wait(core, 2))) {
......
......@@ -82,6 +82,8 @@ head907d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
break;
}
bounds |= 0x00000001;
} else {
bounds |= 0x00000100;
}
if ((push = evo_wait(core, 2))) {
......
......@@ -23,10 +23,6 @@
#include <nvif/cl507b.h>
static const struct nv50_wimm_func
oimm507b = {
};
static int
oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_wndw *wndw)
......@@ -52,5 +48,5 @@ oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
int
oimm507b_init(struct nouveau_drm *drm, s32 oclass, struct nv50_wndw *wndw)
{
return oimm507b_init_(&oimm507b, drm, oclass, wndw);
return oimm507b_init_(&curs507a, drm, oclass, wndw);
}
......@@ -32,7 +32,7 @@ nv50_ovly_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw)
int version;
int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
} ovlys[] = {
{ GK104_DISP_OVERLAY_CONTROL_DMA, 0, ovly907e_new },
{ GK104_DISP_OVERLAY_CONTROL_DMA, 0, ovly917e_new },
{ GF110_DISP_OVERLAY_CONTROL_DMA, 0, ovly907e_new },
{ GT214_DISP_OVERLAY_CHANNEL_DMA, 0, ovly827e_new },
{ GT200_DISP_OVERLAY_CHANNEL_DMA, 0, ovly827e_new },
......
......@@ -6,11 +6,25 @@ int ovly507e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int ovly507e_new_(const struct nv50_wndw_func *, const u32 *format,
struct nouveau_drm *, int head, s32 oclass,
u32 interlock_data, struct nv50_wndw **);
int ovly507e_acquire(struct nv50_wndw *, struct nv50_wndw_atom *,
struct nv50_head_atom *);
void ovly507e_release(struct nv50_wndw *, struct nv50_wndw_atom *,
struct nv50_head_atom *);
void ovly507e_ntfy_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void ovly507e_ntfy_clr(struct nv50_wndw *);
void ovly507e_image_clr(struct nv50_wndw *);
void ovly507e_scale_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void ovly507e_update(struct nv50_wndw *, u32 *);
extern const u32 ovly827e_format[];
void ovly827e_ntfy_reset(struct nouveau_bo *, u32);
int ovly827e_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
extern const struct nv50_wndw_func ovly907e;
int ovly827e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int ovly907e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int ovly917e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int nv50_ovly_new(struct nouveau_drm *, int head, struct nv50_wndw **);
#endif
......@@ -20,17 +20,149 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ovly.h"
#include "atom.h"
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <nvif/cl507e.h>
#include <nvif/event.h>
void
ovly507e_update(struct nv50_wndw *wndw, u32 *interlock)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 2))) {
evo_mthd(push, 0x0080, 1);
evo_data(push, interlock[NV50_DISP_INTERLOCK_CORE]);
evo_kick(push, &wndw->wndw);
}
}
void
ovly507e_scale_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 4))) {
evo_mthd(push, 0x00e0, 3);
evo_data(push, asyw->scale.sy << 16 | asyw->scale.sx);
evo_data(push, asyw->scale.sh << 16 | asyw->scale.sw);
evo_data(push, asyw->scale.dw);
evo_kick(push, &wndw->wndw);
}
}
void
ovly507e_image_clr(struct nv50_wndw *wndw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 4))) {
evo_mthd(push, 0x0084, 1);
evo_data(push, 0x00000000);
evo_mthd(push, 0x00c0, 1);
evo_data(push, 0x00000000);
evo_kick(push, &wndw->wndw);
}
}
static void
ovly507e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 12))) {
evo_mthd(push, 0x0084, 1);
evo_data(push, asyw->image.interval << 4);
evo_mthd(push, 0x00c0, 1);
evo_data(push, asyw->image.handle[0]);
evo_mthd(push, 0x0100, 1);
evo_data(push, 0x00000002);
evo_mthd(push, 0x0800, 1);
evo_data(push, asyw->image.offset[0] >> 8);
evo_mthd(push, 0x0808, 3);
evo_data(push, asyw->image.h << 16 | asyw->image.w);
evo_data(push, asyw->image.layout << 20 |
(asyw->image.pitch[0] >> 8) << 8 |
asyw->image.blocks[0] << 8 |
asyw->image.blockh);
evo_data(push, asyw->image.kind << 16 |
asyw->image.format << 8 |
asyw->image.colorspace);
evo_kick(push, &wndw->wndw);
}
}
void
ovly507e_ntfy_clr(struct nv50_wndw *wndw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 2))) {
evo_mthd(push, 0x00a4, 1);
evo_data(push, 0x00000000);
evo_kick(push, &wndw->wndw);
}
}
void
ovly507e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 3))) {
evo_mthd(push, 0x00a0, 2);
evo_data(push, asyw->ntfy.awaken << 30 | asyw->ntfy.offset);
evo_data(push, asyw->ntfy.handle);
evo_kick(push, &wndw->wndw);
}
}
void
ovly507e_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
asyh->ovly.cpp = 0;
}
int
ovly507e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
const struct drm_framebuffer *fb = asyw->state.fb;
int ret;
ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
if (ret)
return ret;
asyh->ovly.cpp = fb->format->cpp[0];
return 0;
}
#include "nouveau_bo.h"
static const struct nv50_wndw_func
ovly507e = {
.acquire = ovly507e_acquire,
.release = ovly507e_release,
.ntfy_set = ovly507e_ntfy_set,
.ntfy_clr = ovly507e_ntfy_clr,
.ntfy_reset = base507c_ntfy_reset,
.ntfy_wait_begun = base507c_ntfy_wait_begun,
.image_set = ovly507e_image_set,
.image_clr = ovly507e_image_clr,
.scale_set = ovly507e_scale_set,
.update = ovly507e_update,
};
static const u32
ovly507e_format[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_ARGB1555,
0
};
......@@ -61,6 +193,18 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
return ret;
}
ret = nvif_notify_init(&wndw->wndw.base.user, wndw->notify.func, false,
NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT,
&(struct nvif_notify_uevent_req) {},
sizeof(struct nvif_notify_uevent_req),
sizeof(struct nvif_notify_uevent_rep),
&wndw->notify);
if (ret)
return ret;
wndw->ntfy = NV50_DISP_OVLY_NTFY(wndw->id);
wndw->sema = NV50_DISP_OVLY_SEM0(wndw->id);
wndw->data = 0x00000000;
return 0;
}
......
......@@ -20,17 +20,81 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ovly.h"
#include "atom.h"
#include <nouveau_bo.h>
#include <nvif/cl507e.h>
static void
ovly827e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 12))) {
evo_mthd(push, 0x0084, 1);
evo_data(push, asyw->image.interval << 4);
evo_mthd(push, 0x00c0, 1);
evo_data(push, asyw->image.handle[0]);
evo_mthd(push, 0x0100, 1);
evo_data(push, 0x00000002);
evo_mthd(push, 0x0800, 1);
evo_data(push, asyw->image.offset[0] >> 8);
evo_mthd(push, 0x0808, 3);
evo_data(push, asyw->image.h << 16 | asyw->image.w);
evo_data(push, asyw->image.layout << 20 |
(asyw->image.pitch[0] >> 8) << 8 |
asyw->image.blocks[0] << 8 |
asyw->image.blockh);
evo_data(push, asyw->image.format << 8 |
asyw->image.colorspace);
evo_kick(push, &wndw->wndw);
}
}
int
ovly827e_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset,
struct nvif_device *device)
{
s64 time = nvif_msec(device, 2000ULL,
u32 data = nouveau_bo_rd32(bo, offset / 4 + 3);
if ((data & 0xffff0000) == 0xffff0000)
break;
usleep_range(1, 2);
);
return time < 0 ? time : 0;
}
void
ovly827e_ntfy_reset(struct nouveau_bo *bo, u32 offset)
{
nouveau_bo_wr32(bo, offset / 4 + 0, 0x00000000);
nouveau_bo_wr32(bo, offset / 4 + 1, 0x00000000);
nouveau_bo_wr32(bo, offset / 4 + 2, 0x00000000);
nouveau_bo_wr32(bo, offset / 4 + 3, 0x80000000);
}
static const struct nv50_wndw_func
ovly827e = {
.acquire = ovly507e_acquire,
.release = ovly507e_release,
.ntfy_set = ovly507e_ntfy_set,
.ntfy_clr = ovly507e_ntfy_clr,
.ntfy_reset = ovly827e_ntfy_reset,
.ntfy_wait_begun = ovly827e_ntfy_wait_begun,
.image_set = ovly827e_image_set,
.image_clr = ovly507e_image_clr,
.scale_set = ovly507e_scale_set,
.update = ovly507e_update,
};
const u32
ovly827e_format[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ABGR2101010,
0
};
......
......@@ -20,9 +20,45 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ovly.h"
#include "atom.h"
static const struct nv50_wndw_func
static void
ovly907e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 12))) {
evo_mthd(push, 0x0084, 1);
evo_data(push, asyw->image.interval << 4);
evo_mthd(push, 0x00c0, 1);
evo_data(push, asyw->image.handle[0]);
evo_mthd(push, 0x0100, 1);
evo_data(push, 0x00000002);
evo_mthd(push, 0x0400, 1);
evo_data(push, asyw->image.offset[0] >> 8);
evo_mthd(push, 0x0408, 3);
evo_data(push, asyw->image.h << 16 | asyw->image.w);
evo_data(push, asyw->image.layout << 24 |
(asyw->image.pitch[0] >> 8) << 8 |
asyw->image.blocks[0] << 8 |
asyw->image.blockh);
evo_data(push, asyw->image.format << 8 |
asyw->image.colorspace);
evo_kick(push, &wndw->wndw);
}
}
const struct nv50_wndw_func
ovly907e = {
.acquire = ovly507e_acquire,
.release = ovly507e_release,
.ntfy_set = ovly507e_ntfy_set,
.ntfy_clr = ovly507e_ntfy_clr,
.ntfy_reset = ovly827e_ntfy_reset,
.ntfy_wait_begun = ovly827e_ntfy_wait_begun,
.image_set = ovly907e_image_set,
.image_clr = ovly507e_image_clr,
.scale_set = ovly507e_scale_set,
.update = ovly507e_update,
};
int
......
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ovly.h"
static const u32
ovly917e_format[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
0
};
int
ovly917e_new(struct nouveau_drm *drm, int head, s32 oclass,
struct nv50_wndw **pwndw)
{
return ovly507e_new_(&ovly907e, ovly917e_format, drm, head, oclass,
0x00000004 << (head * 4), pwndw);
}
......@@ -146,6 +146,7 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
wndw->func->xlut_set(wndw, asyw);
}
if (asyw->set.scale) wndw->func->scale_set(wndw, asyw);
if (asyw->set.point) {
wndw->immd->point(wndw, asyw);
wndw->immd->update(wndw, interlock);
......@@ -180,6 +181,20 @@ nv50_wndw_atomic_check_release(struct nv50_wndw *wndw,
asyw->sema.handle = 0;
}
static int
nv50_wndw_atomic_check_acquire_yuv(struct nv50_wndw_atom *asyw)
{
switch (asyw->state.fb->format->format) {
case DRM_FORMAT_YUYV: asyw->image.format = 0x28; break;
case DRM_FORMAT_UYVY: asyw->image.format = 0x29; break;
default:
WARN_ON(1);
return -EINVAL;
}
asyw->image.colorspace = 1;
return 0;
}
static int
nv50_wndw_atomic_check_acquire_rgb(struct nv50_wndw_atom *asyw)
{
......@@ -197,9 +212,9 @@ nv50_wndw_atomic_check_acquire_rgb(struct nv50_wndw_atom *asyw)
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010: asyw->image.format = 0xdf; break;
default:
WARN_ON(1);
return -EINVAL;
}
asyw->image.colorspace = 0;
return 0;
}
......@@ -221,8 +236,11 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, bool modeset,
asyw->image.kind = fb->nvbo->kind;
ret = nv50_wndw_atomic_check_acquire_rgb(asyw);
if (ret)
return ret;
if (ret) {
ret = nv50_wndw_atomic_check_acquire_yuv(asyw);
if (ret)
return ret;
}
if (asyw->image.kind) {
asyw->image.layout = 0;
......@@ -247,6 +265,17 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, bool modeset,
asyw->set.image = wndw->func->image_set != NULL;
}
if (wndw->func->scale_set) {
asyw->scale.sx = asyw->state.src_x >> 16;
asyw->scale.sy = asyw->state.src_y >> 16;
asyw->scale.sw = asyw->state.src_w >> 16;
asyw->scale.sh = asyw->state.src_h >> 16;
asyw->scale.dw = asyw->state.crtc_w;
asyw->scale.dh = asyw->state.crtc_h;
if (memcmp(&armw->scale, &asyw->scale, sizeof(asyw->scale)))
asyw->set.scale = true;
}
if (wndw->immd) {
asyw->point.x = asyw->state.crtc_x;
asyw->point.y = asyw->state.crtc_y;
......
......@@ -70,15 +70,21 @@ struct nv50_wndw_func {
void (*xlut_clr)(struct nv50_wndw *);
void (*image_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
void (*image_clr)(struct nv50_wndw *);
void (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
void (*update)(struct nv50_wndw *, u32 *interlock);
};
extern const struct drm_plane_funcs nv50_wndw;
void base507c_ntfy_reset(struct nouveau_bo *, u32);
int base507c_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
struct nv50_wimm_func {
void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *);
void (*update)(struct nv50_wndw *, u32 *interlock);
};
extern const struct nv50_wimm_func curs507a;
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment