Found this while trying to make some changes to the kms_cursor_crc test. curs507a_acquire checks that the width and height of the cursor framebuffer are equal (asyw->image.{w,h}). This isn't entirely correct though, as the height of the cursor can be larger than the size of the cursor, as long as the width is the same as the cursor size and there's no framebuffer offset. Note that I'm not entirely sure why this wasn't previously breaking kms_cursor_crc tests - they all set up cursors with the height being one pixel larger than the actual size of the cursor. But this seems to fix things, and the code before was definitely incorrect - so it's not really worth looking into further imho. Changes since v1: * Don't use crtc_w everywhere for determining cursor layout, just use fb size again * Change check so that we only check that the w/h of the cursor plane is the same, the width of the scanout surface is the same as the framebuffer width, and that there's no offset being used for the cursor surface. Signed-off-by: Lyude Paul <lyude@redhat.com> Cc: Martin Peres <martin.peres@mupuf.org> Cc: Jeremy Cline <jcline@redhat.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Reviewed-by: Karol Herbst <kherbst@redhat.com> Signed-off-by: Karol Herbst <kherbst@redhat.com> Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/10
185 lines
5.1 KiB
C
185 lines
5.1 KiB
C
/*
|
|
* 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 "curs.h"
|
|
#include "core.h"
|
|
#include "head.h"
|
|
|
|
#include <nvif/cl507a.h>
|
|
#include <nvif/timer.h>
|
|
|
|
#include <nvhw/class/cl507a.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_plane_helper.h>
|
|
|
|
bool
|
|
curs507a_space(struct nv50_wndw *wndw)
|
|
{
|
|
nvif_msec(&nouveau_drm(wndw->plane.dev)->client.device, 100,
|
|
if (NVIF_TV32(&wndw->wimm.base.user, NV507A, FREE, COUNT, >=, 4))
|
|
return true;
|
|
);
|
|
|
|
WARN_ON(1);
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
curs507a_update(struct nv50_wndw *wndw, u32 *interlock)
|
|
{
|
|
struct nvif_object *user = &wndw->wimm.base.user;
|
|
int ret = nvif_chan_wait(&wndw->wimm, 1);
|
|
if (ret == 0) {
|
|
NVIF_WR32(user, NV507A, UPDATE,
|
|
NVDEF(NV507A, UPDATE, INTERLOCK_WITH_CORE, DISABLE));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
curs507a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
|
|
{
|
|
struct nvif_object *user = &wndw->wimm.base.user;
|
|
int ret = nvif_chan_wait(&wndw->wimm, 1);
|
|
if (ret == 0) {
|
|
NVIF_WR32(user, NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT,
|
|
NVVAL(NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT, X, asyw->point.x) |
|
|
NVVAL(NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT, Y, asyw->point.y));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
const struct nv50_wimm_func
|
|
curs507a = {
|
|
.point = curs507a_point,
|
|
.update = curs507a_update,
|
|
};
|
|
|
|
static void
|
|
curs507a_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh,
|
|
struct nv50_wndw_atom *asyw)
|
|
{
|
|
u32 handle = nv50_disp(wndw->plane.dev)->core->chan.vram.handle;
|
|
u32 offset = asyw->image.offset[0];
|
|
if (asyh->curs.handle != handle || asyh->curs.offset != offset) {
|
|
asyh->curs.handle = handle;
|
|
asyh->curs.offset = offset;
|
|
asyh->set.curs = asyh->curs.visible;
|
|
}
|
|
}
|
|
|
|
static void
|
|
curs507a_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
|
|
struct nv50_head_atom *asyh)
|
|
{
|
|
asyh->curs.visible = false;
|
|
}
|
|
|
|
static int
|
|
curs507a_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
|
|
struct nv50_head_atom *asyh)
|
|
{
|
|
struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
|
|
struct nv50_head *head = nv50_head(asyw->state.crtc);
|
|
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);
|
|
asyh->curs.visible = asyw->state.visible;
|
|
if (ret || !asyh->curs.visible)
|
|
return ret;
|
|
|
|
if (asyw->state.crtc_w != asyw->state.crtc_h) {
|
|
NV_ATOMIC(drm, "Plane width/height must be equal for cursors\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (asyw->image.w != asyw->state.crtc_w) {
|
|
NV_ATOMIC(drm, "Plane width must be equal to fb width for cursors (height can be larger though)\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (asyw->state.src_x || asyw->state.src_y) {
|
|
NV_ATOMIC(drm, "Cursor planes do not support framebuffer offsets\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = head->func->curs_layout(head, asyw, asyh);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return head->func->curs_format(head, asyw, asyh);
|
|
}
|
|
|
|
static const u32
|
|
curs507a_format[] = {
|
|
DRM_FORMAT_ARGB8888,
|
|
0
|
|
};
|
|
|
|
static const struct nv50_wndw_func
|
|
curs507a_wndw = {
|
|
.acquire = curs507a_acquire,
|
|
.release = curs507a_release,
|
|
.prepare = curs507a_prepare,
|
|
};
|
|
|
|
int
|
|
curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
|
|
int head, s32 oclass, u32 interlock_data,
|
|
struct nv50_wndw **pwndw)
|
|
{
|
|
struct nv50_disp_cursor_v0 args = {
|
|
.head = head,
|
|
};
|
|
struct nv50_disp *disp = nv50_disp(drm->dev);
|
|
struct nv50_wndw *wndw;
|
|
int ret;
|
|
|
|
ret = nv50_wndw_new_(&curs507a_wndw, drm->dev, DRM_PLANE_TYPE_CURSOR,
|
|
"curs", head, curs507a_format, BIT(head),
|
|
NV50_DISP_INTERLOCK_CURS, interlock_data, &wndw);
|
|
if (*pwndw = wndw, ret)
|
|
return ret;
|
|
|
|
ret = nvif_object_ctor(&disp->disp->object, "kmsCurs", 0, oclass,
|
|
&args, sizeof(args), &wndw->wimm.base.user);
|
|
if (ret) {
|
|
NV_ERROR(drm, "curs%04x allocation failed: %d\n", oclass, ret);
|
|
return ret;
|
|
}
|
|
|
|
nvif_object_map(&wndw->wimm.base.user, NULL, 0);
|
|
wndw->immd = func;
|
|
wndw->ctxdma.parent = NULL;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
curs507a_new(struct nouveau_drm *drm, int head, s32 oclass,
|
|
struct nv50_wndw **pwndw)
|
|
{
|
|
return curs507a_new_(&curs507a, drm, head, oclass,
|
|
0x00000001 << (head * 8), pwndw);
|
|
}
|