2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-23 04:34:11 +08:00

drm/nouveau/kms/gv100: initial support

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2018-05-08 20:39:48 +10:00
parent 290ffeafcc
commit facaed62b4
21 changed files with 918 additions and 7 deletions

View File

@ -6,6 +6,7 @@ nouveau-y += dispnv50/core507d.o
nouveau-y += dispnv50/core827d.o
nouveau-y += dispnv50/core907d.o
nouveau-y += dispnv50/core917d.o
nouveau-y += dispnv50/corec37d.o
nouveau-y += dispnv50/dac507d.o
nouveau-y += dispnv50/dac907d.o
@ -14,14 +15,20 @@ nouveau-y += dispnv50/pior507d.o
nouveau-y += dispnv50/sor507d.o
nouveau-y += dispnv50/sor907d.o
nouveau-y += dispnv50/sorc37d.o
nouveau-y += dispnv50/head.o
nouveau-y += dispnv50/head507d.o
nouveau-y += dispnv50/head827d.o
nouveau-y += dispnv50/head907d.o
nouveau-y += dispnv50/head917d.o
nouveau-y += dispnv50/headc37d.o
nouveau-y += dispnv50/wimm.o
nouveau-y += dispnv50/wimmc37b.o
nouveau-y += dispnv50/wndw.o
nouveau-y += dispnv50/wndwc37e.o
nouveau-y += dispnv50/base.o
nouveau-y += dispnv50/base507c.o
@ -32,6 +39,7 @@ nouveau-y += dispnv50/base917c.o
nouveau-y += dispnv50/curs.o
nouveau-y += dispnv50/curs507a.o
nouveau-y += dispnv50/curs907a.o
nouveau-y += dispnv50/cursc37a.o
nouveau-y += dispnv50/oimm.o
nouveau-y += dispnv50/oimm507b.o

View File

@ -54,6 +54,9 @@ struct nv50_head_atom {
u64 offset:40;
u8 buffer:1;
u8 mode:4;
u8 size:2;
u8 range:2;
u8 output_mode:2;
} olut;
struct {
@ -77,7 +80,7 @@ struct nv50_head_atom {
u32 handle;
u64 offset:40;
u8 layout:2;
u8 format:1;
u8 format:8;
} curs;
struct {
@ -166,6 +169,9 @@ struct nv50_wndw_atom {
u8 buffer:1;
u8 enable:2;
u8 mode:4;
u8 size:2;
u8 range:2;
u8 output_mode:2;
} i;
} xlut;

View File

@ -42,6 +42,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core **pcore)
int version;
int (*new)(struct nouveau_drm *, s32, struct nv50_core **);
} cores[] = {
{ GV100_DISP_CORE_CHANNEL_DMA, 0, corec37d_new },
{ GP102_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
{ GP100_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
{ GM200_DISP_CORE_CHANNEL_DMA, 0, core917d_new },

View File

@ -44,4 +44,7 @@ extern const struct nv50_outp_func dac907d;
extern const struct nv50_outp_func sor907d;
int core917d_new(struct nouveau_drm *, s32, struct nv50_core **);
int corec37d_new(struct nouveau_drm *, s32, struct nv50_core **);
extern const struct nv50_outp_func sorc37d;
#endif

View File

@ -0,0 +1,110 @@
/*
* 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 "core.h"
#include "head.h"
#include <nouveau_bo.h>
static void
corec37d_update(struct nv50_core *core, u32 *interlock, bool ntfy)
{
u32 *push;
if ((push = evo_wait(&core->chan, 9))) {
if (ntfy) {
evo_mthd(push, 0x020c, 1);
evo_data(push, 0x00001000 | NV50_DISP_CORE_NTFY);
}
evo_mthd(push, 0x0218, 2);
evo_data(push, interlock[NV50_DISP_INTERLOCK_CURS]);
evo_data(push, interlock[NV50_DISP_INTERLOCK_WNDW]);
evo_mthd(push, 0x0200, 1);
evo_data(push, 0x00000001);
if (ntfy) {
evo_mthd(push, 0x020c, 1);
evo_data(push, 0x00000000);
}
evo_kick(push, &core->chan);
}
}
int
corec37d_ntfy_wait_done(struct nouveau_bo *bo, u32 offset,
struct nvif_device *device)
{
u32 data;
s64 time = nvif_msec(device, 2000ULL,
data = nouveau_bo_rd32(bo, offset / 4 + 0);
if ((data & 0xc0000000) == 0x80000000)
break;
usleep_range(1, 2);
);
return time < 0 ? time : 0;
}
void
corec37d_ntfy_init(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, 0x00000000);
}
void
corec37d_init(struct nv50_core *core)
{
const u32 windows = 8; /*XXX*/
u32 *push, i;
if ((push = evo_wait(&core->chan, 2 + 6 * windows + 2))) {
evo_mthd(push, 0x0208, 1);
evo_data(push, core->chan.sync.handle);
for (i = 0; i < windows; i++) {
evo_mthd(push, 0x1000 + (i * 0x080), 3);
evo_data(push, i >> 1);
evo_data(push, 0x00000017);
evo_data(push, 0x00000000);
evo_mthd(push, 0x1010 + (i * 0x080), 1);
evo_data(push, 0x00127fff);
}
evo_mthd(push, 0x0200, 1);
evo_data(push, 0x00000001);
evo_kick(push, &core->chan);
}
}
static const struct nv50_core_func
corec37d = {
.init = corec37d_init,
.ntfy_init = corec37d_ntfy_init,
.ntfy_wait_done = corec37d_ntfy_wait_done,
.update = corec37d_update,
.head = &headc37d,
.sor = &sorc37d,
};
int
corec37d_new(struct nouveau_drm *drm, s32 oclass, struct nv50_core **pcore)
{
return core507d_new_(&corec37d, drm, oclass, pcore);
}

View File

@ -31,6 +31,7 @@ nv50_curs_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw)
int version;
int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
} curses[] = {
{ GV100_DISP_CURSOR, 0, cursc37a_new },
{ GK104_DISP_CURSOR, 0, curs907a_new },
{ GF110_DISP_CURSOR, 0, curs907a_new },
{ GT214_DISP_CURSOR, 0, curs507a_new },

View File

@ -8,6 +8,7 @@ int curs507a_new_(const struct nv50_wimm_func *, struct nouveau_drm *,
struct nv50_wndw **);
int curs907a_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int cursc37a_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int nv50_curs_new(struct nouveau_drm *, int head, struct nv50_wndw **);
#endif

View File

@ -0,0 +1,50 @@
/*
* 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 "atom.h"
static void
cursc37a_update(struct nv50_wndw *wndw, u32 *interlock)
{
nvif_wr32(&wndw->wimm.base.user, 0x0200, 0x00000001);
}
static void
cursc37a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
nvif_wr32(&wndw->wimm.base.user, 0x0208, asyw->point.y << 16 |
asyw->point.x);
}
static const struct nv50_wimm_func
cursc37a = {
.point = cursc37a_point,
.update = cursc37a_update,
};
int
cursc37a_new(struct nouveau_drm *drm, int head, s32 oclass,
struct nv50_wndw **pwndw)
{
return curs507a_new_(&cursc37a, drm, head, oclass,
0x00000001 << head, pwndw);
}

View File

@ -154,6 +154,9 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
if (ret)
return ret;
if (!syncbuf)
return 0;
ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY,
&(struct nv_dma_v0) {
.target = NV_DMA_V0_TARGET_VRAM,
@ -2170,6 +2173,9 @@ nv50_display_create(struct drm_device *dev)
goto out;
/* create crtc objects to represent the hw heads */
if (disp->disp->object.oclass >= GV100_DISP)
crtcs = nvif_rd32(&device->object, 0x610060) & 0xff;
else
if (disp->disp->object.oclass >= GF110_DISP)
crtcs = nvif_rd32(&device->object, 0x612004) & 0xf;
else

View File

@ -36,11 +36,15 @@ struct nv50_disp_interlock {
NV50_DISP_INTERLOCK_CURS,
NV50_DISP_INTERLOCK_BASE,
NV50_DISP_INTERLOCK_OVLY,
NV50_DISP_INTERLOCK_WNDW,
NV50_DISP_INTERLOCK_WIMM,
NV50_DISP_INTERLOCK__SIZE
} type;
u32 data;
};
void corec37d_ntfy_init(struct nouveau_bo *, u32);
struct nv50_chan {
struct nvif_object user;
struct nvif_device *device;

View File

@ -475,7 +475,16 @@ nv50_head_create(struct drm_device *dev, int index)
head->func = disp->core->func->head;
head->base.index = index;
ret = nv50_base_new(drm, head->base.index, &wndw);
if (disp->disp->object.oclass < GV100_DISP) {
ret = nv50_ovly_new(drm, head->base.index, &wndw);
ret = nv50_base_new(drm, head->base.index, &wndw);
} else {
ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_OVERLAY,
head->base.index * 2 + 1, &wndw);
ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_PRIMARY,
head->base.index * 2 + 0, &wndw);
}
if (ret == 0)
ret = nv50_curs_new(drm, head->base.index, &curs);
if (ret) {
@ -495,8 +504,6 @@ nv50_head_create(struct drm_device *dev, int index)
goto out;
}
/* allocate overlay resources */
ret = nv50_ovly_new(drm, head->base.index, &wndw);
out:
if (ret)
nv50_head_destroy(crtc);

View File

@ -71,4 +71,8 @@ void head907d_procamp(struct nv50_head *, struct nv50_head_atom *);
void head907d_or(struct nv50_head *, struct nv50_head_atom *);
extern const struct nv50_head_func head917d;
int head917d_curs_layout(struct nv50_head *, struct nv50_wndw_atom *,
struct nv50_head_atom *);
extern const struct nv50_head_func headc37d;
#endif

View File

@ -63,7 +63,7 @@ head917d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
}
}
static int
int
head917d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{

View File

@ -0,0 +1,212 @@
/*
* 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 "head.h"
#include "atom.h"
#include "core.h"
static void
headc37d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 2))) {
/*XXX: This is a dirty hack until OR depth handling is
* improved later for deep colour etc.
*/
switch (asyh->or.depth) {
case 6: asyh->or.depth = 5; break;
case 5: asyh->or.depth = 4; break;
case 2: asyh->or.depth = 1; break;
case 0: asyh->or.depth = 4; break;
default:
WARN_ON(1);
break;
}
evo_mthd(push, 0x2004 + (head->base.index * 0x400), 1);
evo_data(push, 0x00000001 |
asyh->or.depth << 4 |
asyh->or.nvsync << 3 |
asyh->or.nhsync << 2);
evo_kick(push, core);
}
}
static void
headc37d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 2))) {
evo_mthd(push, 0x2000 + (head->base.index * 0x400), 1);
evo_data(push, 0x80000000 |
asyh->procamp.sat.sin << 16 |
asyh->procamp.sat.cos << 4);
evo_kick(push, core);
}
}
static void
headc37d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 2))) {
evo_mthd(push, 0x2018 + (head->base.index * 0x0400), 1);
evo_data(push, asyh->dither.mode << 8 |
asyh->dither.bits << 4 |
asyh->dither.enable);
evo_kick(push, core);
}
}
static void
headc37d_curs_clr(struct nv50_head *head)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 4))) {
evo_mthd(push, 0x209c + head->base.index * 0x400, 1);
evo_data(push, 0x000000cf);
evo_mthd(push, 0x2088 + head->base.index * 0x400, 1);
evo_data(push, 0x00000000);
evo_kick(push, core);
}
}
static void
headc37d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 7))) {
evo_mthd(push, 0x209c + head->base.index * 0x400, 2);
evo_data(push, 0x80000000 |
asyh->curs.layout << 8 |
asyh->curs.format << 0);
evo_data(push, 0x000072ff);
evo_mthd(push, 0x2088 + head->base.index * 0x400, 1);
evo_data(push, asyh->curs.handle);
evo_mthd(push, 0x2090 + head->base.index * 0x400, 1);
evo_data(push, asyh->curs.offset >> 8);
evo_kick(push, core);
}
}
static int
headc37d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
asyh->curs.format = asyw->image.format;
return 0;
}
static void
headc37d_olut_clr(struct nv50_head *head)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 2))) {
evo_mthd(push, 0x20ac + (head->base.index * 0x400), 1);
evo_data(push, 0x00000000);
evo_kick(push, core);
}
}
static void
headc37d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 4))) {
evo_mthd(push, 0x20a4 + (head->base.index * 0x400), 3);
evo_data(push, asyh->olut.output_mode << 8 |
asyh->olut.range << 4 |
asyh->olut.size);
evo_data(push, asyh->olut.offset >> 8);
evo_data(push, asyh->olut.handle);
evo_kick(push, core);
}
}
static void
headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
{
asyh->olut.mode = 2;
asyh->olut.size = 0;
asyh->olut.range = 0;
asyh->olut.output_mode = 1;
}
static void
headc37d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
struct nv50_head_mode *m = &asyh->mode;
u32 *push;
if ((push = evo_wait(core, 12))) {
evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5);
evo_data(push, (m->v.active << 16) | m->h.active );
evo_data(push, (m->v.synce << 16) | m->h.synce );
evo_data(push, (m->v.blanke << 16) | m->h.blanke );
evo_data(push, (m->v.blanks << 16) | m->h.blanks );
evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
evo_mthd(push, 0x200c + (head->base.index * 0x400), 1);
evo_data(push, m->clock * 1000);
evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1);
evo_data(push, m->clock * 1000);
/*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
evo_data(push, 0x00000124);
evo_kick(push, core);
}
}
static void
headc37d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
{
struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
u32 *push;
if ((push = evo_wait(core, 4))) {
evo_mthd(push, 0x204c + (head->base.index * 0x400), 1);
evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
evo_mthd(push, 0x2058 + (head->base.index * 0x400), 1);
evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
evo_kick(push, core);
}
}
const struct nv50_head_func
headc37d = {
.view = headc37d_view,
.mode = headc37d_mode,
.olut = headc37d_olut,
.olut_set = headc37d_olut_set,
.olut_clr = headc37d_olut_clr,
.curs_layout = head917d_curs_layout,
.curs_format = headc37d_curs_format,
.curs_set = headc37d_curs_set,
.curs_clr = headc37d_curs_clr,
.dither = headc37d_dither,
.procamp = headc37d_procamp,
.or = headc37d_or,
};

View File

@ -0,0 +1,39 @@
/*
* 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 "core.h"
static void
sorc37d_ctrl(struct nv50_core *core, int or, u32 ctrl,
struct nv50_head_atom *asyh)
{
u32 *push;
if ((push = evo_wait(&core->chan, 2))) {
evo_mthd(push, 0x0300 + (or * 0x20), 1);
evo_data(push, ctrl);
evo_kick(push, &core->chan);
}
}
const struct nv50_outp_func
sorc37d = {
.ctrl = sorc37d_ctrl,
};

View File

@ -0,0 +1,47 @@
/*
* 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 "wimm.h"
#include <nvif/class.h>
int
nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw)
{
struct {
s32 oclass;
int version;
int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *);
} wimms[] = {
{ GV100_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
{}
};
struct nv50_disp *disp = nv50_disp(drm->dev);
int cid;
cid = nvif_mclass(&disp->disp->object, wimms);
if (cid < 0) {
NV_ERROR(drm, "No supported window immediate class\n");
return cid;
}
return wimms[cid].init(drm, wimms[cid].oclass, wndw);
}

View File

@ -0,0 +1,8 @@
#ifndef __NV50_KMS_WIMM_H__
#define __NV50_KMS_WIMM_H__
#include "wndw.h"
int nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *);
int wimmc37b_init(struct nouveau_drm *, s32, struct nv50_wndw *);
#endif

View File

@ -0,0 +1,86 @@
/*
* 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 "wimm.h"
#include "atom.h"
#include "wndw.h"
#include <nvif/clc37b.h>
static void
wimmc37b_update(struct nv50_wndw *wndw, u32 *interlock)
{
u32 *push;
if ((push = evo_wait(&wndw->wimm, 2))) {
evo_mthd(push, 0x0200, 1);
if (interlock[NV50_DISP_INTERLOCK_WNDW] & wndw->interlock.data)
evo_data(push, 0x00000003);
else
evo_data(push, 0x00000001);
evo_kick(push, &wndw->wimm);
}
}
static void
wimmc37b_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wimm, 2))) {
evo_mthd(push, 0x0208, 1);
evo_data(push, asyw->point.y << 16 | asyw->point.x);
evo_kick(push, &wndw->wimm);
}
}
static const struct nv50_wimm_func
wimmc37b = {
.point = wimmc37b_point,
.update = wimmc37b_update,
};
static int
wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_wndw *wndw)
{
struct nvc37b_window_imm_channel_dma_v0 args = {
.pushbuf = 0xb0007b00 | wndw->id,
.index = wndw->id,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
int ret;
ret = nv50_dmac_create(&drm->client.device, &disp->disp->object,
&oclass, 0, &args, sizeof(args), 0,
&wndw->wimm);
if (ret) {
NV_ERROR(drm, "wimm%04x allocation failed: %d\n", oclass, ret);
return ret;
}
wndw->immd = func;
return 0;
}
int
wimmc37b_init(struct nouveau_drm *drm, s32 oclass, struct nv50_wndw *wndw)
{
return wimmc37b_init_(&wimmc37b, drm, oclass, wndw);
}

View File

@ -20,6 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wndw.h"
#include "wimm.h"
#include <nvif/class.h>
#include <nvif/cl0002.h>
@ -148,11 +149,15 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
if (asyw->set.scale) wndw->func->scale_set(wndw, asyw);
if (asyw->set.point) {
if (asyw->set.point = false, asyw->set.mask)
interlock[wndw->interlock.type] |= wndw->interlock.data;
interlock[NV50_DISP_INTERLOCK_WIMM] |= wndw->interlock.data;
wndw->immd->point(wndw, asyw);
wndw->immd->update(wndw, interlock);
} else {
interlock[wndw->interlock.type] |= wndw->interlock.data;
}
interlock[wndw->interlock.type] |= wndw->interlock.data;
}
void
@ -605,3 +610,32 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
wndw->notify.func = nv50_wndw_notify;
return 0;
}
int
nv50_wndw_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
struct nv50_wndw **pwndw)
{
struct {
s32 oclass;
int version;
int (*new)(struct nouveau_drm *, enum drm_plane_type,
int, s32, struct nv50_wndw **);
} wndws[] = {
{ GV100_DISP_WINDOW_CHANNEL_DMA, 0, wndwc37e_new },
{}
};
struct nv50_disp *disp = nv50_disp(drm->dev);
int cid, ret;
cid = nvif_mclass(&disp->disp->object, wndws);
if (cid < 0) {
NV_ERROR(drm, "No supported window class\n");
return cid;
}
ret = wndws[cid].new(drm, type, index, wndws[cid].oclass, pwndw);
if (ret)
return ret;
return nv50_wimm_init(drm, *pwndw);
}

View File

@ -87,4 +87,10 @@ struct nv50_wimm_func {
};
extern const struct nv50_wimm_func curs507a;
int wndwc37e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
struct nv50_wndw **);
int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,
struct nv50_wndw **);
#endif

View File

@ -0,0 +1,278 @@
/*
* 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 "wndw.h"
#include "atom.h"
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <nouveau_bo.h>
#include <nvif/clc37e.h>
static void
wndwc37e_ilut_clr(struct nv50_wndw *wndw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 2))) {
evo_mthd(push, 0x02b8, 1);
evo_data(push, 0x00000000);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 4))) {
evo_mthd(push, 0x02b0, 3);
evo_data(push, asyw->xlut.i.output_mode << 8 |
asyw->xlut.i.range << 4 |
asyw->xlut.i.size);
evo_data(push, asyw->xlut.i.offset >> 8);
evo_data(push, asyw->xlut.handle);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
asyw->xlut.i.mode = 2;
asyw->xlut.i.size = 0;
asyw->xlut.i.range = 0;
asyw->xlut.i.output_mode = 1;
}
static void
wndwc37e_image_clr(struct nv50_wndw *wndw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 4))) {
evo_mthd(push, 0x0308, 1);
evo_data(push, 0x00000000);
evo_mthd(push, 0x0240, 1);
evo_data(push, 0x00000000);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if (!(push = evo_wait(&wndw->wndw, 25)))
return;
evo_mthd(push, 0x0308, 1);
evo_data(push, asyw->image.mode << 4 | asyw->image.interval);
evo_mthd(push, 0x0224, 4);
evo_data(push, asyw->image.h << 16 | asyw->image.w);
evo_data(push, asyw->image.layout << 4 | asyw->image.blockh);
evo_data(push, asyw->image.colorspace << 8 | asyw->image.format);
evo_data(push, asyw->image.blocks[0] | (asyw->image.pitch[0] >> 6));
evo_mthd(push, 0x0240, 1);
evo_data(push, asyw->image.handle[0]);
evo_mthd(push, 0x0260, 1);
evo_data(push, asyw->image.offset[0] >> 8);
evo_mthd(push, 0x0290, 1);
evo_data(push, (asyw->state.src_y >> 16) << 16 |
(asyw->state.src_x >> 16));
evo_mthd(push, 0x0298, 1);
evo_data(push, (asyw->state.src_h >> 16) << 16 |
(asyw->state.src_w >> 16));
evo_mthd(push, 0x02a4, 1);
evo_data(push, asyw->state.crtc_h << 16 |
asyw->state.crtc_w);
/*XXX: Composition-related stuff. Need to implement properly. */
evo_mthd(push, 0x02ec, 1);
evo_data(push, (2 - (wndw->id & 1)) << 4);
evo_mthd(push, 0x02f4, 5);
evo_data(push, 0x00000011);
evo_data(push, 0xffff0000);
evo_data(push, 0xffff0000);
evo_data(push, 0xffff0000);
evo_data(push, 0xffff0000);
evo_kick(push, &wndw->wndw);
}
static void
wndwc37e_ntfy_clr(struct nv50_wndw *wndw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 2))) {
evo_mthd(push, 0x021c, 1);
evo_data(push, 0x00000000);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 3))) {
evo_mthd(push, 0x021c, 2);
evo_data(push, asyw->ntfy.handle);
evo_data(push, asyw->ntfy.offset | asyw->ntfy.awaken);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_sema_clr(struct nv50_wndw *wndw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 2))) {
evo_mthd(push, 0x0218, 1);
evo_data(push, 0x00000000);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 5))) {
evo_mthd(push, 0x020c, 4);
evo_data(push, asyw->sema.offset);
evo_data(push, asyw->sema.acquire);
evo_data(push, asyw->sema.release);
evo_data(push, asyw->sema.handle);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_update(struct nv50_wndw *wndw, u32 *interlock)
{
u32 *push;
if ((push = evo_wait(&wndw->wndw, 5))) {
evo_mthd(push, 0x0370, 2);
evo_data(push, interlock[NV50_DISP_INTERLOCK_CURS] << 1 |
interlock[NV50_DISP_INTERLOCK_CORE]);
evo_data(push, interlock[NV50_DISP_INTERLOCK_WNDW]);
evo_mthd(push, 0x0200, 1);
if (interlock[NV50_DISP_INTERLOCK_WIMM] & wndw->interlock.data)
evo_data(push, 0x00001001);
else
evo_data(push, 0x00000001);
evo_kick(push, &wndw->wndw);
}
}
static void
wndwc37e_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
}
static int
wndwc37e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
return drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
}
static const u32
wndwc37e_format[] = {
DRM_FORMAT_C8,
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
0
};
static const struct nv50_wndw_func
wndwc37e = {
.acquire = wndwc37e_acquire,
.release = wndwc37e_release,
.sema_set = wndwc37e_sema_set,
.sema_clr = wndwc37e_sema_clr,
.ntfy_set = wndwc37e_ntfy_set,
.ntfy_clr = wndwc37e_ntfy_clr,
.ntfy_reset = corec37d_ntfy_init,
.ntfy_wait_begun = base507c_ntfy_wait_begun,
.ilut = wndwc37e_ilut,
.xlut_set = wndwc37e_ilut_set,
.xlut_clr = wndwc37e_ilut_clr,
.image_set = wndwc37e_image_set,
.image_clr = wndwc37e_image_clr,
.update = wndwc37e_update,
};
static int
wndwc37e_new_(const struct nv50_wndw_func *func, struct nouveau_drm *drm,
enum drm_plane_type type, int index, s32 oclass, u32 heads,
struct nv50_wndw **pwndw)
{
struct nvc37e_window_channel_dma_v0 args = {
.pushbuf = 0xb0007e00 | index,
.index = index,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw;
int ret;
ret = nv50_wndw_new_(func, drm->dev, type, "wndw", index,
wndwc37e_format, heads, NV50_DISP_INTERLOCK_WNDW,
BIT(index), &wndw);
if (*pwndw = wndw, ret)
return ret;
ret = nv50_dmac_create(&drm->client.device, &disp->disp->object,
&oclass, 0, &args, sizeof(args),
disp->sync->bo.offset, &wndw->wndw);
if (ret) {
NV_ERROR(drm, "qndw%04x allocation failed: %d\n", oclass, ret);
return ret;
}
wndw->ntfy = NV50_DISP_WNDW_NTFY(wndw->id);
wndw->sema = NV50_DISP_WNDW_SEM0(wndw->id);
wndw->data = 0x00000000;
return 0;
}
int
wndwc37e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
s32 oclass, struct nv50_wndw **pwndw)
{
return wndwc37e_new_(&wndwc37e, drm, type, index, oclass,
BIT(index >> 1), pwndw);
}