drm/nouveau/kms/nv50: separate out cursor channel commit

This commit separates the calculation of EVO state from the commit, in
order to make the same code useful for atomic modesetting.

The legacy interfaces have been wrapped on top of them.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2016-11-04 17:20:36 +10:00
parent 973f10c2d3
commit 22e927d2f8

View File

@ -316,34 +316,6 @@ nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp,
&pioc->base);
}
/******************************************************************************
* Cursor Immediate
*****************************************************************************/
struct nv50_curs {
struct nv50_pioc base;
};
static int
nv50_curs_create(struct nvif_device *device, struct nvif_object *disp,
int head, struct nv50_curs *curs)
{
struct nv50_disp_cursor_v0 args = {
.head = head,
};
static const s32 oclass[] = {
GK104_DISP_CURSOR,
GF110_DISP_CURSOR,
GT214_DISP_CURSOR,
G82_DISP_CURSOR,
NV50_DISP_CURSOR,
0
};
return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
&curs->base);
}
/******************************************************************************
* Overlay Immediate
*****************************************************************************/
@ -566,7 +538,6 @@ nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp,
struct nv50_head {
struct nouveau_crtc base;
struct nouveau_bo *image;
struct nv50_curs curs;
struct nv50_ovly ovly;
struct nv50_oimm oimm;
@ -574,10 +545,10 @@ struct nv50_head {
struct nv50_head_atom asy;
struct nv50_base *_base;
struct nv50_curs *_curs;
};
#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
#define nv50_curs(c) (&nv50_head(c)->curs)
#define nv50_ovly(c) (&nv50_head(c)->ovly)
#define nv50_oimm(c) (&nv50_head(c)->oimm)
#define nv50_chan(c) (&(c)->base.base)
@ -993,6 +964,152 @@ nv50_wndw_ctor(const struct nv50_wndw_func *func, struct drm_device *dev,
return 0;
}
/******************************************************************************
* Cursor plane
*****************************************************************************/
#define nv50_curs(p) container_of((p), struct nv50_curs, wndw)
struct nv50_curs {
struct nv50_wndw wndw;
struct nvif_object chan;
};
static u32
nv50_curs_update(struct nv50_wndw *wndw, u32 interlock)
{
struct nv50_curs *curs = nv50_curs(wndw);
nvif_wr32(&curs->chan, 0x0080, 0x00000000);
return 0;
}
static void
nv50_curs_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
struct nv50_curs *curs = nv50_curs(wndw);
nvif_wr32(&curs->chan, 0x0084, (asyw->point.y << 16) | asyw->point.x);
}
static void
nv50_curs_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh,
struct nv50_wndw_atom *asyw)
{
asyh->curs.handle = nv50_disp(wndw->plane.dev)->mast.base.vram.handle;
asyh->curs.offset = asyw->image.offset;
asyh->set.curs = asyh->curs.visible;
}
static void
nv50_curs_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
asyh->curs.visible = false;
}
static int
nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
int ret;
ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip,
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;
switch (asyw->state.fb->width) {
case 32: asyh->curs.layout = 0; break;
case 64: asyh->curs.layout = 1; break;
default:
return -EINVAL;
}
if (asyw->state.fb->width != asyw->state.fb->height)
return -EINVAL;
switch (asyw->state.fb->pixel_format) {
case DRM_FORMAT_ARGB8888: asyh->curs.format = 1; break;
default:
WARN_ON(1);
return -EINVAL;
}
return 0;
}
static void *
nv50_curs_dtor(struct nv50_wndw *wndw)
{
struct nv50_curs *curs = nv50_curs(wndw);
nvif_object_fini(&curs->chan);
return curs;
}
static const u32
nv50_curs_format[] = {
DRM_FORMAT_ARGB8888,
};
static const struct nv50_wndw_func
nv50_curs = {
.dtor = nv50_curs_dtor,
.acquire = nv50_curs_acquire,
.release = nv50_curs_release,
.prepare = nv50_curs_prepare,
.point = nv50_curs_point,
.update = nv50_curs_update,
};
static int
nv50_curs_new(struct nouveau_drm *drm, struct nv50_head *head,
struct nv50_curs **pcurs)
{
static const struct nvif_mclass curses[] = {
{ GK104_DISP_CURSOR, 0 },
{ GF110_DISP_CURSOR, 0 },
{ GT214_DISP_CURSOR, 0 },
{ G82_DISP_CURSOR, 0 },
{ NV50_DISP_CURSOR, 0 },
{}
};
struct nv50_disp_cursor_v0 args = {
.head = head->base.index,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_curs *curs;
int cid, ret;
cid = nvif_mclass(disp->disp, curses);
if (cid < 0) {
NV_ERROR(drm, "No supported cursor immediate class\n");
return cid;
}
if (!(curs = *pcurs = kzalloc(sizeof(*curs), GFP_KERNEL)))
return -ENOMEM;
ret = nv50_wndw_ctor(&nv50_curs, drm->dev, DRM_PLANE_TYPE_CURSOR,
"curs", head->base.index, &disp->mast.base,
nv50_curs_format, ARRAY_SIZE(nv50_curs_format),
&curs->wndw);
if (ret) {
kfree(curs);
return ret;
}
ret = nvif_object_init(disp->disp, 0, curses[cid].oclass, &args,
sizeof(args), &curs->chan);
if (ret) {
NV_ERROR(drm, "curs%04x allocation failed: %d\n",
curses[cid].oclass, ret);
return ret;
}
return 0;
}
/******************************************************************************
* Primary plane
*****************************************************************************/
@ -2418,10 +2535,13 @@ static int
nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nv50_curs *curs = nv50_curs(crtc);
struct nv50_chan *chan = nv50_chan(curs);
nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
nvif_wr32(&chan->user, 0x0080, 0x00000000);
struct nv50_wndw *wndw = &nv50_head(crtc)->_curs->wndw;
struct nv50_wndw_atom *asyw = &wndw->asy;
asyw->point.x = x;
asyw->point.y = y;
asyw->set.point = true;
nv50_wndw_flush_set(wndw, 0, asyw);
nv_crtc->cursor_saved_x = x;
nv_crtc->cursor_saved_y = y;
@ -2468,7 +2588,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
nv50_dmac_destroy(&head->ovly.base, disp->disp);
nv50_pioc_destroy(&head->oimm.base);
nv50_pioc_destroy(&head->curs.base);
/*XXX: this shouldn't be necessary, but the core doesn't call
* disconnect() during the cleanup paths
@ -2520,6 +2639,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
struct nv50_disp *disp = nv50_disp(dev);
struct nv50_head *head;
struct nv50_base *base;
struct nv50_curs *curs;
struct drm_crtc *crtc;
int ret, i;
@ -2538,6 +2658,8 @@ nv50_crtc_create(struct drm_device *dev, int index)
}
ret = nv50_base_new(drm, head, &base);
if (ret == 0)
ret = nv50_curs_new(drm, head, &curs);
if (ret) {
kfree(head);
return ret;
@ -2545,6 +2667,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
crtc = &head->base.base;
head->_base = base;
head->_curs = curs;
drm_crtc_init(dev, crtc, &nv50_crtc_func);
drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
@ -2563,11 +2686,6 @@ nv50_crtc_create(struct drm_device *dev, int index)
nouveau_bo_ref(NULL, &head->base.lut.nvbo);
}
if (ret)
goto out;
/* allocate cursor resources */
ret = nv50_curs_create(device, disp->disp, index, &head->curs);
if (ret)
goto out;