提交 acbe9ecf 编写于 作者: B Ben Skeggs 提交者: Dave Airlie

drm/nouveau/disp: merge head/outp/ior code into chipset files

No changes to code at all here, just shuffling it around and removing
a bunch of (now unnecessary) forward-declarations from headers.
Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
Reviewed-by: NLyude Paul <lyude@redhat.com>
Signed-off-by: NDave Airlie <airlied@redhat.com>
上级 168c0299
...@@ -44,7 +44,7 @@ struct nvkm_disp { ...@@ -44,7 +44,7 @@ struct nvkm_disp {
struct nvkm_gpuobj *inst; struct nvkm_gpuobj *inst;
struct nvkm_ramht *ramht; struct nvkm_ramht *ramht;
struct nv50_disp_chan *chan[81]; struct nvkm_disp_chan *chan[81];
struct { struct {
spinlock_t lock; spinlock_t lock;
......
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/disp/base.o nvkm-y += nvkm/engine/disp/base.o
nvkm-y += nvkm/engine/disp/chan.o
nvkm-y += nvkm/engine/disp/conn.o
nvkm-y += nvkm/engine/disp/dp.o
nvkm-y += nvkm/engine/disp/hdmi.o
nvkm-y += nvkm/engine/disp/head.o
nvkm-y += nvkm/engine/disp/ior.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/vga.o
nvkm-y += nvkm/engine/disp/nv04.o nvkm-y += nvkm/engine/disp/nv04.o
nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/nv50.o
nvkm-y += nvkm/engine/disp/g84.o nvkm-y += nvkm/engine/disp/g84.o
...@@ -18,98 +27,8 @@ nvkm-y += nvkm/engine/disp/gp102.o ...@@ -18,98 +27,8 @@ nvkm-y += nvkm/engine/disp/gp102.o
nvkm-y += nvkm/engine/disp/gv100.o nvkm-y += nvkm/engine/disp/gv100.o
nvkm-y += nvkm/engine/disp/tu102.o nvkm-y += nvkm/engine/disp/tu102.o
nvkm-y += nvkm/engine/disp/ga102.o nvkm-y += nvkm/engine/disp/ga102.o
nvkm-y += nvkm/engine/disp/vga.o
nvkm-y += nvkm/engine/disp/head.o
nvkm-y += nvkm/engine/disp/headnv04.o
nvkm-y += nvkm/engine/disp/headnv50.o
nvkm-y += nvkm/engine/disp/headgf119.o
nvkm-y += nvkm/engine/disp/headgv100.o
nvkm-y += nvkm/engine/disp/ior.o
nvkm-y += nvkm/engine/disp/dacnv50.o
nvkm-y += nvkm/engine/disp/dacgf119.o
nvkm-y += nvkm/engine/disp/piornv50.o
nvkm-y += nvkm/engine/disp/sornv50.o
nvkm-y += nvkm/engine/disp/sorg84.o
nvkm-y += nvkm/engine/disp/sorg94.o
nvkm-y += nvkm/engine/disp/sormcp77.o
nvkm-y += nvkm/engine/disp/sorgt215.o
nvkm-y += nvkm/engine/disp/sormcp89.o
nvkm-y += nvkm/engine/disp/sorgf119.o
nvkm-y += nvkm/engine/disp/sorgk104.o
nvkm-y += nvkm/engine/disp/sorgm107.o
nvkm-y += nvkm/engine/disp/sorgm200.o
nvkm-y += nvkm/engine/disp/sorgp100.o
nvkm-y += nvkm/engine/disp/sorgv100.o
nvkm-y += nvkm/engine/disp/sortu102.o
nvkm-y += nvkm/engine/disp/sorga102.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/dp.o
nvkm-y += nvkm/engine/disp/hdagt215.o
nvkm-y += nvkm/engine/disp/hdagf119.o
nvkm-y += nvkm/engine/disp/hdagv100.o
nvkm-y += nvkm/engine/disp/hdmi.o
nvkm-y += nvkm/engine/disp/hdmig84.o
nvkm-y += nvkm/engine/disp/hdmigt215.o
nvkm-y += nvkm/engine/disp/hdmigf119.o
nvkm-y += nvkm/engine/disp/hdmigk104.o
nvkm-y += nvkm/engine/disp/hdmigm200.o
nvkm-y += nvkm/engine/disp/hdmigv100.o
nvkm-y += nvkm/engine/disp/conn.o
nvkm-y += nvkm/engine/disp/rootnv04.o nvkm-y += nvkm/engine/disp/rootnv04.o
nvkm-y += nvkm/engine/disp/rootnv50.o nvkm-y += nvkm/engine/disp/rootnv50.o
nvkm-y += nvkm/engine/disp/capsgv100.o
nvkm-y += nvkm/engine/disp/channv50.o
nvkm-y += nvkm/engine/disp/changf119.o
nvkm-y += nvkm/engine/disp/changv100.o
nvkm-y += nvkm/engine/disp/dmacnv50.o
nvkm-y += nvkm/engine/disp/dmacgf119.o
nvkm-y += nvkm/engine/disp/dmacgp102.o
nvkm-y += nvkm/engine/disp/dmacgv100.o
nvkm-y += nvkm/engine/disp/basenv50.o
nvkm-y += nvkm/engine/disp/baseg84.o
nvkm-y += nvkm/engine/disp/basegf119.o
nvkm-y += nvkm/engine/disp/basegp102.o
nvkm-y += nvkm/engine/disp/corenv50.o
nvkm-y += nvkm/engine/disp/coreg84.o
nvkm-y += nvkm/engine/disp/coreg94.o
nvkm-y += nvkm/engine/disp/coregf119.o
nvkm-y += nvkm/engine/disp/coregk104.o
nvkm-y += nvkm/engine/disp/coregp102.o
nvkm-y += nvkm/engine/disp/coregv100.o
nvkm-y += nvkm/engine/disp/ovlynv50.o
nvkm-y += nvkm/engine/disp/ovlyg84.o
nvkm-y += nvkm/engine/disp/ovlygt200.o
nvkm-y += nvkm/engine/disp/ovlygf119.o
nvkm-y += nvkm/engine/disp/ovlygk104.o
nvkm-y += nvkm/engine/disp/ovlygp102.o
nvkm-y += nvkm/engine/disp/wimmgv100.o
nvkm-y += nvkm/engine/disp/wndwgv100.o
nvkm-y += nvkm/engine/disp/piocnv50.o
nvkm-y += nvkm/engine/disp/piocgf119.o
nvkm-y += nvkm/engine/disp/cursnv50.o
nvkm-y += nvkm/engine/disp/cursgf119.o
nvkm-y += nvkm/engine/disp/cursgp102.o
nvkm-y += nvkm/engine/disp/cursgv100.o
nvkm-y += nvkm/engine/disp/oimmnv50.o
nvkm-y += nvkm/engine/disp/oimmgf119.o
nvkm-y += nvkm/engine/disp/oimmgp102.o
nvkm-y += nvkm/engine/disp/udisp.o nvkm-y += nvkm/engine/disp/udisp.o
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
g84_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x0008c4 },
{ 0x0088, 0x0008d0 },
{ 0x008c, 0x0008dc },
{ 0x0090, 0x0008e4 },
{ 0x0094, 0x610884 },
{ 0x00a0, 0x6108a0 },
{ 0x00a4, 0x610878 },
{ 0x00c0, 0x61086c },
{ 0x00c4, 0x610800 },
{ 0x00c8, 0x61080c },
{ 0x00cc, 0x610818 },
{ 0x00e0, 0x610858 },
{ 0x00e4, 0x610860 },
{ 0x00e8, 0x6108ac },
{ 0x00ec, 0x6108b4 },
{ 0x00fc, 0x610824 },
{ 0x0100, 0x610894 },
{ 0x0104, 0x61082c },
{ 0x0110, 0x6108bc },
{ 0x0114, 0x61088c },
{}
}
};
static const struct nv50_disp_chan_mthd
g84_disp_base_mthd = {
.name = "Base",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &g84_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_base_mthd_image },
{}
}
};
int
g84_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&nv50_disp_dmac_func, &g84_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
gf119_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x661080 },
{ 0x0084, 0x661084 },
{ 0x0088, 0x661088 },
{ 0x008c, 0x66108c },
{ 0x0090, 0x661090 },
{ 0x0094, 0x661094 },
{ 0x00a0, 0x6610a0 },
{ 0x00a4, 0x6610a4 },
{ 0x00c0, 0x6610c0 },
{ 0x00c4, 0x6610c4 },
{ 0x00c8, 0x6610c8 },
{ 0x00cc, 0x6610cc },
{ 0x00e0, 0x6610e0 },
{ 0x00e4, 0x6610e4 },
{ 0x00e8, 0x6610e8 },
{ 0x00ec, 0x6610ec },
{ 0x00fc, 0x6610fc },
{ 0x0100, 0x661100 },
{ 0x0104, 0x661104 },
{ 0x0108, 0x661108 },
{ 0x010c, 0x66110c },
{ 0x0110, 0x661110 },
{ 0x0114, 0x661114 },
{ 0x0118, 0x661118 },
{ 0x011c, 0x66111c },
{ 0x0130, 0x661130 },
{ 0x0134, 0x661134 },
{ 0x0138, 0x661138 },
{ 0x013c, 0x66113c },
{ 0x0140, 0x661140 },
{ 0x0144, 0x661144 },
{ 0x0148, 0x661148 },
{ 0x014c, 0x66114c },
{ 0x0150, 0x661150 },
{ 0x0154, 0x661154 },
{ 0x0158, 0x661158 },
{ 0x015c, 0x66115c },
{ 0x0160, 0x661160 },
{ 0x0164, 0x661164 },
{ 0x0168, 0x661168 },
{ 0x016c, 0x66116c },
{}
}
};
static const struct nv50_disp_mthd_list
gf119_disp_base_mthd_image = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0400, 0x661400 },
{ 0x0404, 0x661404 },
{ 0x0408, 0x661408 },
{ 0x040c, 0x66140c },
{ 0x0410, 0x661410 },
{}
}
};
const struct nv50_disp_chan_mthd
gf119_disp_base_mthd = {
.name = "Base",
.addr = 0x001000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gf119_disp_base_mthd_base },
{ "Image", 2, &gf119_disp_base_mthd_image },
{}
}
};
int
gf119_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&gf119_disp_dmac_func, &gf119_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2016 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.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
int
gp102_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&gp102_disp_dmac_func, &gf119_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include "head.h"
#include <core/client.h>
#include <nvif/cl507c.h>
#include <nvif/unpack.h>
int
nv50_disp_base_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nvkm_disp *disp, int chid,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
union {
struct nv50_disp_base_channel_dma_v0 v0;
} *args = argv;
struct nvkm_object *parent = oclass->parent;
int head, ret = -ENOSYS;
u64 push;
nvif_ioctl(parent, "create disp base channel dma size %d\n", argc);
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp base channel dma vers %d "
"pushbuf %016llx head %d\n",
args->v0.version, args->v0.pushbuf, args->v0.head);
if (!nvkm_head_find(disp, args->v0.head))
return -EINVAL;
push = args->v0.pushbuf;
head = args->v0.head;
} else
return ret;
return nv50_disp_dmac_new_(func, mthd, disp, chid + head,
head, push, oclass, pobject);
}
static const struct nv50_disp_mthd_list
nv50_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x0008c4 },
{ 0x0088, 0x0008d0 },
{ 0x008c, 0x0008dc },
{ 0x0090, 0x0008e4 },
{ 0x0094, 0x610884 },
{ 0x00a0, 0x6108a0 },
{ 0x00a4, 0x610878 },
{ 0x00c0, 0x61086c },
{ 0x00e0, 0x610858 },
{ 0x00e4, 0x610860 },
{ 0x00e8, 0x6108ac },
{ 0x00ec, 0x6108b4 },
{ 0x0100, 0x610894 },
{ 0x0110, 0x6108bc },
{ 0x0114, 0x61088c },
{}
}
};
const struct nv50_disp_mthd_list
nv50_disp_base_mthd_image = {
.mthd = 0x0400,
.addr = 0x000000,
.data = {
{ 0x0800, 0x6108f0 },
{ 0x0804, 0x6108fc },
{ 0x0808, 0x61090c },
{ 0x080c, 0x610914 },
{ 0x0810, 0x610904 },
{}
}
};
static const struct nv50_disp_chan_mthd
nv50_disp_base_mthd = {
.name = "Base",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_base_mthd_image },
{}
}
};
int
nv50_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&nv50_disp_dmac_func, &nv50_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2020 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.
*/
#define gv100_disp_caps(p) container_of((p), struct gv100_disp_caps, object)
#include "priv.h"
struct gv100_disp_caps {
struct nvkm_object object;
struct nvkm_disp *disp;
};
static int
gv100_disp_caps_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size)
{
struct gv100_disp_caps *caps = gv100_disp_caps(object);
struct nvkm_device *device = caps->disp->engine.subdev.device;
*type = NVKM_OBJECT_MAP_IO;
*addr = 0x640000 + device->func->resource_addr(device, 0);
*size = 0x1000;
return 0;
}
static const struct nvkm_object_func
gv100_disp_caps = {
.map = gv100_disp_caps_map,
};
int
gv100_disp_caps_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
struct gv100_disp_caps *caps;
if (!(caps = kzalloc(sizeof(*caps), GFP_KERNEL)))
return -ENOMEM;
*pobject = &caps->object;
nvkm_object_ctor(&gv100_disp_caps, oclass, &caps->object);
caps->disp = disp;
return 0;
}
/* /*
* Copyright 2012 Red Hat Inc. * Copyright 2021 Red Hat Inc.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -18,186 +18,42 @@ ...@@ -18,186 +18,42 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * 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 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/ */
#include "channv50.h" #include "chan.h"
#include <core/client.h>
#include <core/notify.h>
#include <core/oproxy.h> #include <core/oproxy.h>
#include <core/ramht.h> #include <core/ramht.h>
#include <engine/dma.h>
#include <nvif/cl507d.h> #include <nvif/cl507d.h>
#include <nvif/event.h>
#include <nvif/unpack.h>
static void
nv50_disp_mthd_list(struct nvkm_disp *disp, int debug, u32 base, int c,
const struct nv50_disp_mthd_list *list, int inst)
{
struct nvkm_subdev *subdev = &disp->engine.subdev;
struct nvkm_device *device = subdev->device;
int i;
for (i = 0; list->data[i].mthd; i++) {
if (list->data[i].addr) {
u32 next = nvkm_rd32(device, list->data[i].addr + base + 0);
u32 prev = nvkm_rd32(device, list->data[i].addr + base + c);
u32 mthd = list->data[i].mthd + (list->mthd * inst);
const char *name = list->data[i].name;
char mods[16];
if (prev != next)
snprintf(mods, sizeof(mods), "-> %08x", next);
else
snprintf(mods, sizeof(mods), "%13c", ' ');
nvkm_printk_(subdev, debug, info,
"\t%04x: %08x %s%s%s\n",
mthd, prev, mods, name ? " // " : "",
name ? name : "");
}
}
}
void
nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug)
{
struct nvkm_disp *disp = chan->disp;
struct nvkm_subdev *subdev = &disp->engine.subdev;
const struct nv50_disp_chan_mthd *mthd = chan->mthd;
const struct nv50_disp_mthd_list *list;
int i, j;
if (debug > subdev->debug)
return;
if (!mthd)
return;
for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) {
u32 base = chan->head * mthd->addr;
for (j = 0; j < mthd->data[i].nr; j++, base += list->addr) {
const char *cname = mthd->name;
const char *sname = "";
char cname_[16], sname_[16];
if (mthd->addr) {
snprintf(cname_, sizeof(cname_), "%s %d",
mthd->name, chan->chid.user);
cname = cname_;
}
if (mthd->data[i].nr > 1) {
snprintf(sname_, sizeof(sname_), " - %s %d",
mthd->data[i].name, j);
sname = sname_;
}
nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname);
nv50_disp_mthd_list(disp, debug, base, mthd->prev,
list, j);
}
}
}
static void
nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nvkm_disp *disp = container_of(event, typeof(*disp), uevent);
struct nvkm_device *device = disp->engine.subdev.device;
nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000000 << index);
nvkm_wr32(device, 0x610020, 0x00000001 << index);
}
static void
nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{
struct nvkm_disp *disp = container_of(event, typeof(*disp), uevent);
struct nvkm_device *device = disp->engine.subdev.device;
nvkm_wr32(device, 0x610020, 0x00000001 << index);
nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index);
}
void
nv50_disp_chan_uevent_send(struct nvkm_disp *disp, int chid)
{
struct nvif_notify_uevent_rep {
} rep;
nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep));
}
int
nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
union {
struct nvif_notify_uevent_req none;
} *args = data;
int ret = -ENOSYS;
if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = chan->chid.user;
return 0;
}
return ret;
}
const struct nvkm_event_func
nv50_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
.init = nv50_disp_chan_uevent_init,
.fini = nv50_disp_chan_uevent_fini,
};
u64
nv50_disp_chan_user(struct nv50_disp_chan *chan, u64 *psize)
{
*psize = 0x1000;
return 0x640000 + (chan->chid.user * 0x1000);
}
void
nv50_disp_chan_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 mask = 0x00010001 << chan->chid.user;
const u32 data = en ? 0x00010000 << chan->chid.user : 0x00000000;
nvkm_mask(device, 0x610028, mask, data);
}
static int static int
nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) nvkm_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device; struct nvkm_device *device = chan->disp->engine.subdev.device;
u64 size, base = chan->func->user(chan, &size); u64 size, base = chan->func->user(chan, &size);
*data = nvkm_rd32(device, base + addr); *data = nvkm_rd32(device, base + addr);
return 0; return 0;
} }
static int static int
nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) nvkm_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device; struct nvkm_device *device = chan->disp->engine.subdev.device;
u64 size, base = chan->func->user(chan, &size); u64 size, base = chan->func->user(chan, &size);
nvkm_wr32(device, base + addr, data); nvkm_wr32(device, base + addr, data);
return 0; return 0;
} }
static int static int
nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, nvkm_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent)
struct nvkm_event **pevent)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_disp *disp = chan->disp; struct nvkm_disp *disp = chan->disp;
switch (type) { switch (type) {
case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
*pevent = &disp->uevent; *pevent = &disp->uevent;
...@@ -205,54 +61,56 @@ nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, ...@@ -205,54 +61,56 @@ nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type,
default: default:
break; break;
} }
return -EINVAL; return -EINVAL;
} }
static int static int
nv50_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc, nvkm_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size) enum nvkm_object_map *type, u64 *addr, u64 *size)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device; struct nvkm_device *device = chan->disp->engine.subdev.device;
const u64 base = device->func->resource_addr(device, 0); const u64 base = device->func->resource_addr(device, 0);
*type = NVKM_OBJECT_MAP_IO; *type = NVKM_OBJECT_MAP_IO;
*addr = base + chan->func->user(chan, size); *addr = base + chan->func->user(chan, size);
return 0; return 0;
} }
struct nv50_disp_chan_object { struct nvkm_disp_chan_object {
struct nvkm_oproxy oproxy; struct nvkm_oproxy oproxy;
struct nvkm_disp *disp; struct nvkm_disp *disp;
int hash; int hash;
}; };
static void static void
nv50_disp_chan_child_del_(struct nvkm_oproxy *base) nvkm_disp_chan_child_del_(struct nvkm_oproxy *base)
{ {
struct nv50_disp_chan_object *object = struct nvkm_disp_chan_object *object = container_of(base, typeof(*object), oproxy);
container_of(base, typeof(*object), oproxy);
nvkm_ramht_remove(object->disp->ramht, object->hash); nvkm_ramht_remove(object->disp->ramht, object->hash);
} }
static const struct nvkm_oproxy_func static const struct nvkm_oproxy_func
nv50_disp_chan_child_func_ = { nvkm_disp_chan_child_func_ = {
.dtor[0] = nv50_disp_chan_child_del_, .dtor[0] = nvkm_disp_chan_child_del_,
}; };
static int static int
nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, nvkm_disp_chan_child_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
void *argv, u32 argc, struct nvkm_object **pobject) struct nvkm_object **pobject)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent); struct nvkm_disp_chan *chan = nvkm_disp_chan(oclass->parent);
struct nvkm_disp *disp = chan->disp; struct nvkm_disp *disp = chan->disp;
struct nvkm_device *device = disp->engine.subdev.device; struct nvkm_device *device = disp->engine.subdev.device;
const struct nvkm_device_oclass *sclass = oclass->priv; const struct nvkm_device_oclass *sclass = oclass->priv;
struct nv50_disp_chan_object *object; struct nvkm_disp_chan_object *object;
int ret; int ret;
if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
nvkm_oproxy_ctor(&nv50_disp_chan_child_func_, oclass, &object->oproxy); nvkm_oproxy_ctor(&nvkm_disp_chan_child_func_, oclass, &object->oproxy);
object->disp = disp; object->disp = disp;
*pobject = &object->oproxy.base; *pobject = &object->oproxy.base;
...@@ -260,8 +118,7 @@ nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, ...@@ -260,8 +118,7 @@ nv50_disp_chan_child_new(const struct nvkm_oclass *oclass,
if (ret) if (ret)
return ret; return ret;
object->hash = chan->func->bind(chan, object->oproxy.object, object->hash = chan->func->bind(chan, object->oproxy.object, oclass->handle);
oclass->handle);
if (object->hash < 0) if (object->hash < 0)
return object->hash; return object->hash;
...@@ -269,10 +126,9 @@ nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, ...@@ -269,10 +126,9 @@ nv50_disp_chan_child_new(const struct nvkm_oclass *oclass,
} }
static int static int
nv50_disp_chan_child_get(struct nvkm_object *object, int index, nvkm_disp_chan_child_get(struct nvkm_object *object, int index, struct nvkm_oclass *sclass)
struct nvkm_oclass *sclass)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device; struct nvkm_device *device = chan->disp->engine.subdev.device;
const struct nvkm_device_oclass *oclass = NULL; const struct nvkm_device_oclass *oclass = NULL;
...@@ -284,7 +140,7 @@ nv50_disp_chan_child_get(struct nvkm_object *object, int index, ...@@ -284,7 +140,7 @@ nv50_disp_chan_child_get(struct nvkm_object *object, int index,
if (sclass->engine && sclass->engine->func->base.sclass) { if (sclass->engine && sclass->engine->func->base.sclass) {
sclass->engine->func->base.sclass(sclass, index, &oclass); sclass->engine->func->base.sclass(sclass, index, &oclass);
if (oclass) { if (oclass) {
sclass->ctor = nv50_disp_chan_child_new, sclass->ctor = nvkm_disp_chan_child_new;
sclass->priv = oclass; sclass->priv = oclass;
return 0; return 0;
} }
...@@ -294,59 +150,63 @@ nv50_disp_chan_child_get(struct nvkm_object *object, int index, ...@@ -294,59 +150,63 @@ nv50_disp_chan_child_get(struct nvkm_object *object, int index,
} }
static int static int
nv50_disp_chan_fini(struct nvkm_object *object, bool suspend) nvkm_disp_chan_fini(struct nvkm_object *object, bool suspend)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
chan->func->fini(chan); chan->func->fini(chan);
chan->func->intr(chan, false); chan->func->intr(chan, false);
return 0; return 0;
} }
static int static int
nv50_disp_chan_init(struct nvkm_object *object) nvkm_disp_chan_init(struct nvkm_object *object)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
chan->func->intr(chan, true); chan->func->intr(chan, true);
return chan->func->init(chan); return chan->func->init(chan);
} }
static void * static void *
nv50_disp_chan_dtor(struct nvkm_object *object) nvkm_disp_chan_dtor(struct nvkm_object *object)
{ {
struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_disp *disp = chan->disp; struct nvkm_disp *disp = chan->disp;
if (chan->chid.user >= 0) if (chan->chid.user >= 0)
disp->chan[chan->chid.user] = NULL; disp->chan[chan->chid.user] = NULL;
nvkm_memory_unref(&chan->memory); nvkm_memory_unref(&chan->memory);
return chan; return chan;
} }
static const struct nvkm_object_func static const struct nvkm_object_func
nv50_disp_chan = { nvkm_disp_chan = {
.dtor = nv50_disp_chan_dtor, .dtor = nvkm_disp_chan_dtor,
.init = nv50_disp_chan_init, .init = nvkm_disp_chan_init,
.fini = nv50_disp_chan_fini, .fini = nvkm_disp_chan_fini,
.rd32 = nv50_disp_chan_rd32, .rd32 = nvkm_disp_chan_rd32,
.wr32 = nv50_disp_chan_wr32, .wr32 = nvkm_disp_chan_wr32,
.ntfy = nv50_disp_chan_ntfy, .ntfy = nvkm_disp_chan_ntfy,
.map = nv50_disp_chan_map, .map = nvkm_disp_chan_map,
.sclass = nv50_disp_chan_child_get, .sclass = nvkm_disp_chan_child_get,
}; };
int int
nv50_disp_chan_new_(const struct nv50_disp_chan_func *func, nvkm_disp_chan_new_(const struct nvkm_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd, const struct nvkm_disp_chan_mthd *mthd,
struct nvkm_disp *disp, int ctrl, int user, int head, struct nvkm_disp *disp, int ctrl, int user, int head,
const struct nvkm_oclass *oclass, const struct nvkm_oclass *oclass,
struct nvkm_object **pobject) struct nvkm_object **pobject)
{ {
struct nv50_disp_chan *chan; struct nvkm_disp_chan *chan;
if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
*pobject = &chan->object; *pobject = &chan->object;
nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object); nvkm_object_ctor(&nvkm_disp_chan, oclass, &chan->object);
chan->func = func; chan->func = func;
chan->mthd = mthd; chan->mthd = mthd;
chan->disp = disp; chan->disp = disp;
......
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
#ifndef __NV50_DISP_CHAN_H__ #ifndef __NVKM_DISP_CHAN_H__
#define __NV50_DISP_CHAN_H__ #define __NVKM_DISP_CHAN_H__
#define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object) #define nvkm_disp_chan(p) container_of((p), struct nvkm_disp_chan, object)
#include <core/object.h> #include <core/object.h>
#include "priv.h" #include "priv.h"
struct nv50_disp_root;
struct nv50_disp_chan { struct nvkm_disp_chan {
const struct nv50_disp_chan_func *func; const struct nvkm_disp_chan_func *func;
const struct nv50_disp_chan_mthd *mthd; const struct nvkm_disp_chan_mthd *mthd;
struct nvkm_disp *disp; struct nvkm_disp *disp;
struct { struct {
...@@ -25,65 +24,65 @@ struct nv50_disp_chan { ...@@ -25,65 +24,65 @@ struct nv50_disp_chan {
u32 suspend_put; u32 suspend_put;
}; };
struct nv50_disp_chan_func { struct nvkm_disp_chan_func {
int (*init)(struct nv50_disp_chan *); int (*init)(struct nvkm_disp_chan *);
void (*fini)(struct nv50_disp_chan *); void (*fini)(struct nvkm_disp_chan *);
void (*intr)(struct nv50_disp_chan *, bool en); void (*intr)(struct nvkm_disp_chan *, bool en);
u64 (*user)(struct nv50_disp_chan *, u64 *size); u64 (*user)(struct nvkm_disp_chan *, u64 *size);
int (*bind)(struct nv50_disp_chan *, struct nvkm_object *, u32 handle); int (*bind)(struct nvkm_disp_chan *, struct nvkm_object *, u32 handle);
}; };
int nv50_disp_chan_new_(const struct nv50_disp_chan_func *, int nvkm_disp_chan_new_(const struct nvkm_disp_chan_func *,
const struct nv50_disp_chan_mthd *, const struct nvkm_disp_chan_mthd *,
struct nvkm_disp *, int ctrl, int user, int head, struct nvkm_disp *, int ctrl, int user, int head,
const struct nvkm_oclass *, struct nvkm_object **); const struct nvkm_oclass *, struct nvkm_object **);
int nv50_disp_dmac_new_(const struct nv50_disp_chan_func *, int nv50_disp_dmac_new_(const struct nvkm_disp_chan_func *,
const struct nv50_disp_chan_mthd *, const struct nvkm_disp_chan_mthd *,
struct nvkm_disp *, int chid, int head, u64 push, struct nvkm_disp *, int chid, int head, u64 push,
const struct nvkm_oclass *, struct nvkm_object **); const struct nvkm_oclass *, struct nvkm_object **);
void nv50_disp_chan_intr(struct nv50_disp_chan *, bool); void nv50_disp_chan_intr(struct nvkm_disp_chan *, bool);
u64 nv50_disp_chan_user(struct nv50_disp_chan *, u64 *); u64 nv50_disp_chan_user(struct nvkm_disp_chan *, u64 *);
extern const struct nv50_disp_chan_func nv50_disp_pioc_func; extern const struct nvkm_disp_chan_func nv50_disp_pioc_func;
extern const struct nv50_disp_chan_func nv50_disp_dmac_func; extern const struct nvkm_disp_chan_func nv50_disp_dmac_func;
int nv50_disp_dmac_bind(struct nv50_disp_chan *, struct nvkm_object *, u32); int nv50_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
extern const struct nv50_disp_chan_func nv50_disp_core_func; extern const struct nvkm_disp_chan_func nv50_disp_core_func;
void gf119_disp_chan_intr(struct nv50_disp_chan *, bool); void gf119_disp_chan_intr(struct nvkm_disp_chan *, bool);
extern const struct nv50_disp_chan_func gf119_disp_pioc_func; extern const struct nvkm_disp_chan_func gf119_disp_pioc_func;
extern const struct nv50_disp_chan_func gf119_disp_dmac_func; extern const struct nvkm_disp_chan_func gf119_disp_dmac_func;
void gf119_disp_dmac_fini(struct nv50_disp_chan *); void gf119_disp_dmac_fini(struct nvkm_disp_chan *);
int gf119_disp_dmac_bind(struct nv50_disp_chan *, struct nvkm_object *, u32); int gf119_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
extern const struct nv50_disp_chan_func gf119_disp_core_func; extern const struct nvkm_disp_chan_func gf119_disp_core_func;
void gf119_disp_core_fini(struct nv50_disp_chan *); void gf119_disp_core_fini(struct nvkm_disp_chan *);
extern const struct nv50_disp_chan_func gp102_disp_dmac_func; extern const struct nvkm_disp_chan_func gp102_disp_dmac_func;
u64 gv100_disp_chan_user(struct nv50_disp_chan *, u64 *); u64 gv100_disp_chan_user(struct nvkm_disp_chan *, u64 *);
int gv100_disp_dmac_init(struct nv50_disp_chan *); int gv100_disp_dmac_init(struct nvkm_disp_chan *);
void gv100_disp_dmac_fini(struct nv50_disp_chan *); void gv100_disp_dmac_fini(struct nvkm_disp_chan *);
int gv100_disp_dmac_bind(struct nv50_disp_chan *, struct nvkm_object *, u32); int gv100_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
int nv50_disp_curs_new_(const struct nv50_disp_chan_func *, int nv50_disp_curs_new_(const struct nvkm_disp_chan_func *,
struct nvkm_disp *, int ctrl, int user, struct nvkm_disp *, int ctrl, int user,
const struct nvkm_oclass *, void *argv, u32 argc, const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **); struct nvkm_object **);
int nv50_disp_oimm_new_(const struct nv50_disp_chan_func *, int nv50_disp_oimm_new_(const struct nvkm_disp_chan_func *,
struct nvkm_disp *, int ctrl, int user, struct nvkm_disp *, int ctrl, int user,
const struct nvkm_oclass *, void *argv, u32 argc, const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **); struct nvkm_object **);
int nv50_disp_base_new_(const struct nv50_disp_chan_func *, int nv50_disp_base_new_(const struct nvkm_disp_chan_func *,
const struct nv50_disp_chan_mthd *, const struct nvkm_disp_chan_mthd *,
struct nvkm_disp *, int chid, struct nvkm_disp *, int chid,
const struct nvkm_oclass *, void *argv, u32 argc, const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **); struct nvkm_object **);
int nv50_disp_core_new_(const struct nv50_disp_chan_func *, int nv50_disp_core_new_(const struct nvkm_disp_chan_func *,
const struct nv50_disp_chan_mthd *, const struct nvkm_disp_chan_mthd *,
struct nvkm_disp *, int chid, struct nvkm_disp *, int chid,
const struct nvkm_oclass *oclass, void *argv, u32 argc, const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **); struct nvkm_object **);
int nv50_disp_ovly_new_(const struct nv50_disp_chan_func *, int nv50_disp_ovly_new_(const struct nvkm_disp_chan_func *,
const struct nv50_disp_chan_mthd *, const struct nvkm_disp_chan_mthd *,
struct nvkm_disp *, int chid, struct nvkm_disp *, int chid,
const struct nvkm_oclass *, void *argv, u32 argc, const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **); struct nvkm_object **);
...@@ -148,7 +147,7 @@ int gv100_disp_core_new(const struct nvkm_oclass *, void *, u32, ...@@ -148,7 +147,7 @@ int gv100_disp_core_new(const struct nvkm_oclass *, void *, u32,
int gv100_disp_wndw_new(const struct nvkm_oclass *, void *, u32, int gv100_disp_wndw_new(const struct nvkm_oclass *, void *, u32,
struct nvkm_disp *, struct nvkm_object **); struct nvkm_disp *, struct nvkm_object **);
struct nv50_disp_mthd_list { struct nvkm_disp_mthd_list {
u32 mthd; u32 mthd;
u32 addr; u32 addr;
struct { struct {
...@@ -158,36 +157,36 @@ struct nv50_disp_mthd_list { ...@@ -158,36 +157,36 @@ struct nv50_disp_mthd_list {
} data[]; } data[];
}; };
struct nv50_disp_chan_mthd { struct nvkm_disp_chan_mthd {
const char *name; const char *name;
u32 addr; u32 addr;
s32 prev; s32 prev;
struct { struct {
const char *name; const char *name;
int nr; int nr;
const struct nv50_disp_mthd_list *mthd; const struct nvkm_disp_mthd_list *mthd;
} data[]; } data[];
}; };
void nv50_disp_chan_mthd(struct nv50_disp_chan *, int debug); void nv50_disp_chan_mthd(struct nvkm_disp_chan *, int debug);
extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base; extern const struct nvkm_disp_mthd_list nv50_disp_core_mthd_base;
extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor; extern const struct nvkm_disp_mthd_list nv50_disp_core_mthd_sor;
extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior; extern const struct nvkm_disp_mthd_list nv50_disp_core_mthd_pior;
extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image; extern const struct nvkm_disp_mthd_list nv50_disp_base_mthd_image;
extern const struct nv50_disp_chan_mthd g84_disp_core_mthd; extern const struct nvkm_disp_chan_mthd g84_disp_core_mthd;
extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac; extern const struct nvkm_disp_mthd_list g84_disp_core_mthd_dac;
extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head; extern const struct nvkm_disp_mthd_list g84_disp_core_mthd_head;
extern const struct nv50_disp_chan_mthd g94_disp_core_mthd; extern const struct nvkm_disp_chan_mthd g94_disp_core_mthd;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_base; extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_base;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_dac; extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_dac;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_sor; extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_sor;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_pior; extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_pior;
extern const struct nv50_disp_chan_mthd gf119_disp_base_mthd; extern const struct nvkm_disp_chan_mthd gf119_disp_base_mthd;
extern const struct nv50_disp_chan_mthd gk104_disp_core_mthd; extern const struct nvkm_disp_chan_mthd gk104_disp_core_mthd;
extern const struct nv50_disp_chan_mthd gk104_disp_ovly_mthd; extern const struct nvkm_disp_chan_mthd gk104_disp_ovly_mthd;
#endif #endif
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static void
gf119_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nvkm_disp *disp = container_of(event, typeof(*disp), uevent);
struct nvkm_device *device = disp->engine.subdev.device;
nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000000 << index);
nvkm_wr32(device, 0x61008c, 0x00000001 << index);
}
static void
gf119_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{
struct nvkm_disp *disp = container_of(event, typeof(*disp), uevent);
struct nvkm_device *device = disp->engine.subdev.device;
nvkm_wr32(device, 0x61008c, 0x00000001 << index);
nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000001 << index);
}
const struct nvkm_event_func
gf119_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
.init = gf119_disp_chan_uevent_init,
.fini = gf119_disp_chan_uevent_fini,
};
void
gf119_disp_chan_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 mask = 0x00000001 << chan->chid.user;
if (!en) {
nvkm_mask(device, 0x610090, mask, 0x00000000);
nvkm_mask(device, 0x6100a0, mask, 0x00000000);
} else {
nvkm_mask(device, 0x6100a0, mask, mask);
}
}
/*
* 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 "channv50.h"
const struct nvkm_event_func
gv100_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
};
u64
gv100_disp_chan_user(struct nv50_disp_chan *chan, u64 *psize)
{
*psize = 0x1000;
return 0x690000 + ((chan->chid.user - 1) * 0x1000);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
const struct nv50_disp_mthd_list
g84_disp_core_mthd_dac = {
.mthd = 0x0080,
.addr = 0x000008,
.data = {
{ 0x0400, 0x610b58 },
{ 0x0404, 0x610bdc },
{ 0x0420, 0x610bc4 },
{}
}
};
const struct nv50_disp_mthd_list
g84_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000540,
.data = {
{ 0x0800, 0x610ad8 },
{ 0x0804, 0x610ad0 },
{ 0x0808, 0x610a48 },
{ 0x080c, 0x610a78 },
{ 0x0810, 0x610ac0 },
{ 0x0814, 0x610af8 },
{ 0x0818, 0x610b00 },
{ 0x081c, 0x610ae8 },
{ 0x0820, 0x610af0 },
{ 0x0824, 0x610b08 },
{ 0x0828, 0x610b10 },
{ 0x082c, 0x610a68 },
{ 0x0830, 0x610a60 },
{ 0x0834, 0x000000 },
{ 0x0838, 0x610a40 },
{ 0x0840, 0x610a24 },
{ 0x0844, 0x610a2c },
{ 0x0848, 0x610aa8 },
{ 0x084c, 0x610ab0 },
{ 0x085c, 0x610c5c },
{ 0x0860, 0x610a84 },
{ 0x0864, 0x610a90 },
{ 0x0868, 0x610b18 },
{ 0x086c, 0x610b20 },
{ 0x0870, 0x610ac8 },
{ 0x0874, 0x610a38 },
{ 0x0878, 0x610c50 },
{ 0x0880, 0x610a58 },
{ 0x0884, 0x610a9c },
{ 0x089c, 0x610c68 },
{ 0x08a0, 0x610a70 },
{ 0x08a4, 0x610a50 },
{ 0x08a8, 0x610ae0 },
{ 0x08c0, 0x610b28 },
{ 0x08c4, 0x610b30 },
{ 0x08c8, 0x610b40 },
{ 0x08d4, 0x610b38 },
{ 0x08d8, 0x610b48 },
{ 0x08dc, 0x610b50 },
{ 0x0900, 0x610a18 },
{ 0x0904, 0x610ab8 },
{ 0x0910, 0x610c70 },
{ 0x0914, 0x610c78 },
{}
}
};
const struct nv50_disp_chan_mthd
g84_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
int
g84_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &g84_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
g94_disp_core_mthd_sor = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0600, 0x610794 },
{}
}
};
const struct nv50_disp_chan_mthd
g94_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 4, &g94_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
int
g94_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &g94_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <subdev/timer.h>
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x660080 },
{ 0x0084, 0x660084 },
{ 0x0088, 0x660088 },
{ 0x008c, 0x000000 },
{}
}
};
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_dac = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0180, 0x660180 },
{ 0x0184, 0x660184 },
{ 0x0188, 0x660188 },
{ 0x0190, 0x660190 },
{}
}
};
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_sor = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0200, 0x660200 },
{ 0x0204, 0x660204 },
{ 0x0208, 0x660208 },
{ 0x0210, 0x660210 },
{}
}
};
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_pior = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0300, 0x660300 },
{ 0x0304, 0x660304 },
{ 0x0308, 0x660308 },
{ 0x0310, 0x660310 },
{}
}
};
static const struct nv50_disp_mthd_list
gf119_disp_core_mthd_head = {
.mthd = 0x0300,
.addr = 0x000300,
.data = {
{ 0x0400, 0x660400 },
{ 0x0404, 0x660404 },
{ 0x0408, 0x660408 },
{ 0x040c, 0x66040c },
{ 0x0410, 0x660410 },
{ 0x0414, 0x660414 },
{ 0x0418, 0x660418 },
{ 0x041c, 0x66041c },
{ 0x0420, 0x660420 },
{ 0x0424, 0x660424 },
{ 0x0428, 0x660428 },
{ 0x042c, 0x66042c },
{ 0x0430, 0x660430 },
{ 0x0434, 0x660434 },
{ 0x0438, 0x660438 },
{ 0x0440, 0x660440 },
{ 0x0444, 0x660444 },
{ 0x0448, 0x660448 },
{ 0x044c, 0x66044c },
{ 0x0450, 0x660450 },
{ 0x0454, 0x660454 },
{ 0x0458, 0x660458 },
{ 0x045c, 0x66045c },
{ 0x0460, 0x660460 },
{ 0x0468, 0x660468 },
{ 0x046c, 0x66046c },
{ 0x0470, 0x660470 },
{ 0x0474, 0x660474 },
{ 0x0480, 0x660480 },
{ 0x0484, 0x660484 },
{ 0x048c, 0x66048c },
{ 0x0490, 0x660490 },
{ 0x0494, 0x660494 },
{ 0x0498, 0x660498 },
{ 0x04b0, 0x6604b0 },
{ 0x04b8, 0x6604b8 },
{ 0x04bc, 0x6604bc },
{ 0x04c0, 0x6604c0 },
{ 0x04c4, 0x6604c4 },
{ 0x04c8, 0x6604c8 },
{ 0x04d0, 0x6604d0 },
{ 0x04d4, 0x6604d4 },
{ 0x04e0, 0x6604e0 },
{ 0x04e4, 0x6604e4 },
{ 0x04e8, 0x6604e8 },
{ 0x04ec, 0x6604ec },
{ 0x04f0, 0x6604f0 },
{ 0x04f4, 0x6604f4 },
{ 0x04f8, 0x6604f8 },
{ 0x04fc, 0x6604fc },
{ 0x0500, 0x660500 },
{ 0x0504, 0x660504 },
{ 0x0508, 0x660508 },
{ 0x050c, 0x66050c },
{ 0x0510, 0x660510 },
{ 0x0514, 0x660514 },
{ 0x0518, 0x660518 },
{ 0x051c, 0x66051c },
{ 0x052c, 0x66052c },
{ 0x0530, 0x660530 },
{ 0x054c, 0x66054c },
{ 0x0550, 0x660550 },
{ 0x0554, 0x660554 },
{ 0x0558, 0x660558 },
{ 0x055c, 0x66055c },
{}
}
};
static const struct nv50_disp_chan_mthd
gf119_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gf119_disp_core_mthd_base },
{ "DAC", 3, &gf119_disp_core_mthd_dac },
{ "SOR", 8, &gf119_disp_core_mthd_sor },
{ "PIOR", 4, &gf119_disp_core_mthd_pior },
{ "HEAD", 4, &gf119_disp_core_mthd_head },
{}
}
};
void
gf119_disp_core_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
/* deactivate channel */
nvkm_mask(device, 0x610490, 0x00000010, 0x00000000);
nvkm_mask(device, 0x610490, 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "core fini: %08x\n",
nvkm_rd32(device, 0x610490));
}
chan->suspend_put = nvkm_rd32(device, 0x640000);
}
static int
gf119_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610494, chan->push);
nvkm_wr32(device, 0x610498, 0x00010000);
nvkm_wr32(device, 0x61049c, 0x00000001);
nvkm_mask(device, 0x610490, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000, chan->suspend_put);
nvkm_wr32(device, 0x610490, 0x01000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "core init: %08x\n",
nvkm_rd32(device, 0x610490));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
gf119_disp_core_func = {
.init = gf119_disp_core_init,
.fini = gf119_disp_core_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
int
gf119_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gf119_disp_core_func, &gf119_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
gk104_disp_core_mthd_head = {
.mthd = 0x0300,
.addr = 0x000300,
.data = {
{ 0x0400, 0x660400 },
{ 0x0404, 0x660404 },
{ 0x0408, 0x660408 },
{ 0x040c, 0x66040c },
{ 0x0410, 0x660410 },
{ 0x0414, 0x660414 },
{ 0x0418, 0x660418 },
{ 0x041c, 0x66041c },
{ 0x0420, 0x660420 },
{ 0x0424, 0x660424 },
{ 0x0428, 0x660428 },
{ 0x042c, 0x66042c },
{ 0x0430, 0x660430 },
{ 0x0434, 0x660434 },
{ 0x0438, 0x660438 },
{ 0x0440, 0x660440 },
{ 0x0444, 0x660444 },
{ 0x0448, 0x660448 },
{ 0x044c, 0x66044c },
{ 0x0450, 0x660450 },
{ 0x0454, 0x660454 },
{ 0x0458, 0x660458 },
{ 0x045c, 0x66045c },
{ 0x0460, 0x660460 },
{ 0x0468, 0x660468 },
{ 0x046c, 0x66046c },
{ 0x0470, 0x660470 },
{ 0x0474, 0x660474 },
{ 0x047c, 0x66047c },
{ 0x0480, 0x660480 },
{ 0x0484, 0x660484 },
{ 0x0488, 0x660488 },
{ 0x048c, 0x66048c },
{ 0x0490, 0x660490 },
{ 0x0494, 0x660494 },
{ 0x0498, 0x660498 },
{ 0x04a0, 0x6604a0 },
{ 0x04b0, 0x6604b0 },
{ 0x04b8, 0x6604b8 },
{ 0x04bc, 0x6604bc },
{ 0x04c0, 0x6604c0 },
{ 0x04c4, 0x6604c4 },
{ 0x04c8, 0x6604c8 },
{ 0x04d0, 0x6604d0 },
{ 0x04d4, 0x6604d4 },
{ 0x04e0, 0x6604e0 },
{ 0x04e4, 0x6604e4 },
{ 0x04e8, 0x6604e8 },
{ 0x04ec, 0x6604ec },
{ 0x04f0, 0x6604f0 },
{ 0x04f4, 0x6604f4 },
{ 0x04f8, 0x6604f8 },
{ 0x04fc, 0x6604fc },
{ 0x0500, 0x660500 },
{ 0x0504, 0x660504 },
{ 0x0508, 0x660508 },
{ 0x050c, 0x66050c },
{ 0x0510, 0x660510 },
{ 0x0514, 0x660514 },
{ 0x0518, 0x660518 },
{ 0x051c, 0x66051c },
{ 0x0520, 0x660520 },
{ 0x0524, 0x660524 },
{ 0x052c, 0x66052c },
{ 0x0530, 0x660530 },
{ 0x054c, 0x66054c },
{ 0x0550, 0x660550 },
{ 0x0554, 0x660554 },
{ 0x0558, 0x660558 },
{ 0x055c, 0x66055c },
{}
}
};
const struct nv50_disp_chan_mthd
gk104_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gf119_disp_core_mthd_base },
{ "DAC", 3, &gf119_disp_core_mthd_dac },
{ "SOR", 8, &gf119_disp_core_mthd_sor },
{ "PIOR", 4, &gf119_disp_core_mthd_pior },
{ "HEAD", 4, &gk104_disp_core_mthd_head },
{}
}
};
int
gk104_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gf119_disp_core_func, &gk104_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2016 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.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
#include <subdev/timer.h>
static int
gp102_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x611494, chan->push);
nvkm_wr32(device, 0x611498, 0x00010000);
nvkm_wr32(device, 0x61149c, 0x00000001);
nvkm_mask(device, 0x610490, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000, chan->suspend_put);
nvkm_wr32(device, 0x610490, 0x01000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "core init: %08x\n",
nvkm_rd32(device, 0x610490));
return -EBUSY;
}
return 0;
}
static const struct nv50_disp_chan_func
gp102_disp_core_func = {
.init = gp102_disp_core_init,
.fini = gf119_disp_core_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
int
gp102_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gp102_disp_core_func, &gk104_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* 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 "channv50.h"
#include <subdev/timer.h>
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0200, 0x680200 },
{ 0x0208, 0x680208 },
{ 0x020c, 0x68020c },
{ 0x0210, 0x680210 },
{ 0x0214, 0x680214 },
{ 0x0218, 0x680218 },
{ 0x021c, 0x68021c },
{}
}
};
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_sor = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0300, 0x680300 },
{ 0x0304, 0x680304 },
{ 0x0308, 0x680308 },
{ 0x030c, 0x68030c },
{}
}
};
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_wndw = {
.mthd = 0x0080,
.addr = 0x000080,
.data = {
{ 0x1000, 0x681000 },
{ 0x1004, 0x681004 },
{ 0x1008, 0x681008 },
{ 0x100c, 0x68100c },
{ 0x1010, 0x681010 },
{}
}
};
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000400,
.data = {
{ 0x2000, 0x682000 },
{ 0x2004, 0x682004 },
{ 0x2008, 0x682008 },
{ 0x200c, 0x68200c },
{ 0x2014, 0x682014 },
{ 0x2018, 0x682018 },
{ 0x201c, 0x68201c },
{ 0x2020, 0x682020 },
{ 0x2028, 0x682028 },
{ 0x202c, 0x68202c },
{ 0x2030, 0x682030 },
{ 0x2038, 0x682038 },
{ 0x203c, 0x68203c },
{ 0x2048, 0x682048 },
{ 0x204c, 0x68204c },
{ 0x2050, 0x682050 },
{ 0x2054, 0x682054 },
{ 0x2058, 0x682058 },
{ 0x205c, 0x68205c },
{ 0x2060, 0x682060 },
{ 0x2064, 0x682064 },
{ 0x2068, 0x682068 },
{ 0x206c, 0x68206c },
{ 0x2070, 0x682070 },
{ 0x2074, 0x682074 },
{ 0x2078, 0x682078 },
{ 0x207c, 0x68207c },
{ 0x2080, 0x682080 },
{ 0x2088, 0x682088 },
{ 0x2090, 0x682090 },
{ 0x209c, 0x68209c },
{ 0x20a0, 0x6820a0 },
{ 0x20a4, 0x6820a4 },
{ 0x20a8, 0x6820a8 },
{ 0x20ac, 0x6820ac },
{ 0x2180, 0x682180 },
{ 0x2184, 0x682184 },
{ 0x218c, 0x68218c },
{ 0x2194, 0x682194 },
{ 0x2198, 0x682198 },
{ 0x219c, 0x68219c },
{ 0x21a0, 0x6821a0 },
{ 0x21a4, 0x6821a4 },
{ 0x2214, 0x682214 },
{ 0x2218, 0x682218 },
{}
}
};
static const struct nv50_disp_chan_mthd
gv100_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x008000,
.data = {
{ "Global", 1, &gv100_disp_core_mthd_base },
{ "SOR", 4, &gv100_disp_core_mthd_sor },
{ "WINDOW", 8, &gv100_disp_core_mthd_wndw },
{ "HEAD", 4, &gv100_disp_core_mthd_head },
{}
}
};
static int
gv100_disp_core_idle(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
nvkm_msec(device, 2000,
u32 stat = nvkm_rd32(device, 0x610630);
if ((stat & 0x001f0000) == 0x000b0000)
return 0;
);
return -EBUSY;
}
static u64
gv100_disp_core_user(struct nv50_disp_chan *chan, u64 *psize)
{
*psize = 0x10000;
return 0x680000;
}
static void
gv100_disp_core_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 mask = 0x00000001;
const u32 data = en ? mask : 0;
nvkm_mask(device, 0x611dac, mask, data);
}
static void
gv100_disp_core_fini(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
nvkm_mask(device, 0x6104e0, 0x00000010, 0x00000000);
gv100_disp_core_idle(chan);
nvkm_mask(device, 0x6104e0, 0x00000002, 0x00000000);
chan->suspend_put = nvkm_rd32(device, 0x680000);
}
static int
gv100_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
nvkm_wr32(device, 0x610b24, lower_32_bits(chan->push));
nvkm_wr32(device, 0x610b20, upper_32_bits(chan->push));
nvkm_wr32(device, 0x610b28, 0x00000001);
nvkm_wr32(device, 0x610b2c, 0x00000040);
nvkm_mask(device, 0x6104e0, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x680000, chan->suspend_put);
nvkm_wr32(device, 0x6104e0, 0x00000013);
return gv100_disp_core_idle(chan);
}
static const struct nv50_disp_chan_func
gv100_disp_core = {
.init = gv100_disp_core_init,
.fini = gv100_disp_core_fini,
.intr = gv100_disp_core_intr,
.user = gv100_disp_core_user,
.bind = gv100_disp_dmac_bind,
};
int
gv100_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gv100_disp_core, &gv100_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <core/client.h>
#include <subdev/timer.h>
#include <nvif/cl507d.h>
#include <nvif/unpack.h>
int
nv50_disp_core_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nvkm_disp *disp, int chid,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
union {
struct nv50_disp_core_channel_dma_v0 v0;
} *args = argv;
struct nvkm_object *parent = oclass->parent;
u64 push;
int ret = -ENOSYS;
nvif_ioctl(parent, "create disp core channel dma size %d\n", argc);
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp core channel dma vers %d "
"pushbuf %016llx\n",
args->v0.version, args->v0.pushbuf);
push = args->v0.pushbuf;
} else
return ret;
return nv50_disp_dmac_new_(func, mthd, disp, chid, 0,
push, oclass, pobject);
}
const struct nv50_disp_mthd_list
nv50_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x610bb8 },
{ 0x0088, 0x610b9c },
{ 0x008c, 0x000000 },
{}
}
};
static const struct nv50_disp_mthd_list
nv50_disp_core_mthd_dac = {
.mthd = 0x0080,
.addr = 0x000008,
.data = {
{ 0x0400, 0x610b58 },
{ 0x0404, 0x610bdc },
{ 0x0420, 0x610828 },
{}
}
};
const struct nv50_disp_mthd_list
nv50_disp_core_mthd_sor = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0600, 0x610b70 },
{}
}
};
const struct nv50_disp_mthd_list
nv50_disp_core_mthd_pior = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0700, 0x610b80 },
{}
}
};
static const struct nv50_disp_mthd_list
nv50_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000540,
.data = {
{ 0x0800, 0x610ad8 },
{ 0x0804, 0x610ad0 },
{ 0x0808, 0x610a48 },
{ 0x080c, 0x610a78 },
{ 0x0810, 0x610ac0 },
{ 0x0814, 0x610af8 },
{ 0x0818, 0x610b00 },
{ 0x081c, 0x610ae8 },
{ 0x0820, 0x610af0 },
{ 0x0824, 0x610b08 },
{ 0x0828, 0x610b10 },
{ 0x082c, 0x610a68 },
{ 0x0830, 0x610a60 },
{ 0x0834, 0x000000 },
{ 0x0838, 0x610a40 },
{ 0x0840, 0x610a24 },
{ 0x0844, 0x610a2c },
{ 0x0848, 0x610aa8 },
{ 0x084c, 0x610ab0 },
{ 0x0860, 0x610a84 },
{ 0x0864, 0x610a90 },
{ 0x0868, 0x610b18 },
{ 0x086c, 0x610b20 },
{ 0x0870, 0x610ac8 },
{ 0x0874, 0x610a38 },
{ 0x0880, 0x610a58 },
{ 0x0884, 0x610a9c },
{ 0x08a0, 0x610a70 },
{ 0x08a4, 0x610a50 },
{ 0x08a8, 0x610ae0 },
{ 0x08c0, 0x610b28 },
{ 0x08c4, 0x610b30 },
{ 0x08c8, 0x610b40 },
{ 0x08d4, 0x610b38 },
{ 0x08d8, 0x610b48 },
{ 0x08dc, 0x610b50 },
{ 0x0900, 0x610a18 },
{ 0x0904, 0x610ab8 },
{}
}
};
static const struct nv50_disp_chan_mthd
nv50_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &nv50_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &nv50_disp_core_mthd_head },
{}
}
};
static void
nv50_disp_core_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
/* deactivate channel */
nvkm_mask(device, 0x610200, 0x00000010, 0x00000000);
nvkm_mask(device, 0x610200, 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "core fini: %08x\n",
nvkm_rd32(device, 0x610200));
}
chan->suspend_put = nvkm_rd32(device, 0x640000);
}
static int
nv50_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
/* attempt to unstick channel from some unknown state */
if ((nvkm_rd32(device, 0x610200) & 0x009f0000) == 0x00020000)
nvkm_mask(device, 0x610200, 0x00800000, 0x00800000);
if ((nvkm_rd32(device, 0x610200) & 0x003f0000) == 0x00030000)
nvkm_mask(device, 0x610200, 0x00600000, 0x00600000);
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610204, chan->push);
nvkm_wr32(device, 0x610208, 0x00010000);
nvkm_wr32(device, 0x61020c, 0x00000000);
nvkm_mask(device, 0x610200, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000, chan->suspend_put);
nvkm_wr32(device, 0x610200, 0x01000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "core init: %08x\n",
nvkm_rd32(device, 0x610200));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
nv50_disp_core_func = {
.init = nv50_disp_core_init,
.fini = nv50_disp_core_fini,
.intr = nv50_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = nv50_disp_dmac_bind,
};
int
nv50_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &nv50_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
int
gf119_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 13,
oclass, argv, argc, pobject);
}
/*
* Copyright 2016 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.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
int
gp102_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 17,
oclass, argv, argc, pobject);
}
/*
* 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 "channv50.h"
#include <subdev/timer.h>
static int
gv100_disp_curs_idle(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 soff = (chan->chid.ctrl - 1) * 0x04;
nvkm_msec(device, 2000,
u32 stat = nvkm_rd32(device, 0x610664 + soff);
if ((stat & 0x00070000) == 0x00040000)
return 0;
);
return -EBUSY;
}
static void
gv100_disp_curs_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 mask = 0x00010000 << chan->head;
const u32 data = en ? mask : 0;
nvkm_mask(device, 0x611dac, mask, data);
}
static void
gv100_disp_curs_fini(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 hoff = chan->chid.ctrl * 4;
nvkm_mask(device, 0x6104e0 + hoff, 0x00000010, 0x00000010);
gv100_disp_curs_idle(chan);
nvkm_mask(device, 0x6104e0 + hoff, 0x00000001, 0x00000000);
}
static int
gv100_disp_curs_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
nvkm_wr32(device, 0x6104e0 + chan->chid.ctrl * 4, 0x00000001);
return gv100_disp_curs_idle(chan);
}
static const struct nv50_disp_chan_func
gv100_disp_curs = {
.init = gv100_disp_curs_init,
.fini = gv100_disp_curs_fini,
.intr = gv100_disp_curs_intr,
.user = gv100_disp_chan_user,
};
int
gv100_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&gv100_disp_curs, disp, 73, 73,
oclass, argv, argc, pobject);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include "head.h"
#include <core/client.h>
#include <nvif/cl507a.h>
#include <nvif/unpack.h>
int
nv50_disp_curs_new_(const struct nv50_disp_chan_func *func,
struct nvkm_disp *disp, int ctrl, int user,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
union {
struct nv50_disp_cursor_v0 v0;
} *args = argv;
struct nvkm_object *parent = oclass->parent;
int head, ret = -ENOSYS;
nvif_ioctl(parent, "create disp cursor size %d\n", argc);
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp cursor vers %d head %d\n",
args->v0.version, args->v0.head);
if (!nvkm_head_find(disp, args->v0.head))
return -EINVAL;
head = args->v0.head;
} else
return ret;
return nv50_disp_chan_new_(func, NULL, disp, ctrl + head, user + head,
head, oclass, pobject);
}
int
nv50_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&nv50_disp_pioc_func, disp, 7, 7,
oclass, argv, argc, pobject);
}
/*
* Copyright 2017 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 "ior.h"
static void
gf119_dac_clock(struct nvkm_ior *dac)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
nvkm_mask(device, 0x612280 + doff, 0x07070707, 0x00000000);
}
static void
gf119_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 coff = (state == &dac->asy) * 0x20000 + dac->id * 0x20;
u32 ctrl = nvkm_rd32(device, 0x640180 + coff);
state->proto_evo = (ctrl & 0x00000f00) >> 8;
switch (state->proto_evo) {
case 0: state->proto = CRT; break;
default:
state->proto = UNKNOWN;
break;
}
state->head = ctrl & 0x0000000f;
}
static const struct nvkm_ior_func
gf119_dac = {
.state = gf119_dac_state,
.power = nv50_dac_power,
.sense = nv50_dac_sense,
.clock = gf119_dac_clock,
};
int
gf119_dac_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&gf119_dac, disp, DAC, id);
}
int
gf119_dac_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = (nvkm_rd32(device, 0x612004) & 0x000000f0) >> 4;
return 4;
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "ior.h"
#include <subdev/timer.h>
static void
nv50_dac_clock(struct nvkm_ior *dac)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
nvkm_mask(device, 0x614280 + doff, 0x07070707, 0x00000000);
}
int
nv50_dac_sense(struct nvkm_ior *dac, u32 loadval)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
dac->func->power(dac, false, true, false, false, false);
nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval);
mdelay(9);
udelay(500);
loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000);
dac->func->power(dac, false, false, false, false, false);
if (!(loadval & 0x80000000))
return -ETIMEDOUT;
return (loadval & 0x38000000) >> 27;
}
static void
nv50_dac_power_wait(struct nvkm_device *device, const u32 doff)
{
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
break;
);
}
void
nv50_dac_power(struct nvkm_ior *dac, bool normal, bool pu,
bool data, bool vsync, bool hsync)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
const u32 shift = normal ? 0 : 16;
const u32 state = 0x80000000 | (0x00000040 * ! pu |
0x00000010 * ! data |
0x00000004 * ! vsync |
0x00000001 * ! hsync) << shift;
const u32 field = 0xc0000000 | (0x00000055 << shift);
nv50_dac_power_wait(device, doff);
nvkm_mask(device, 0x61a004 + doff, field, state);
nv50_dac_power_wait(device, doff);
}
static void
nv50_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 coff = dac->id * 8 + (state == &dac->arm) * 4;
u32 ctrl = nvkm_rd32(device, 0x610b58 + coff);
state->proto_evo = (ctrl & 0x00000f00) >> 8;
switch (state->proto_evo) {
case 0: state->proto = CRT; break;
default:
state->proto = UNKNOWN;
break;
}
state->head = ctrl & 0x00000003;
}
static const struct nvkm_ior_func
nv50_dac = {
.state = nv50_dac_state,
.power = nv50_dac_power,
.sense = nv50_dac_sense,
.clock = nv50_dac_clock,
};
int
nv50_dac_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&nv50_dac, disp, DAC, id);
}
int
nv50_dac_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = (nvkm_rd32(device, 0x610184) & 0x00700000) >> 20;
return 3;
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <core/ramht.h>
#include <subdev/timer.h>
int
gf119_disp_dmac_bind(struct nv50_disp_chan *chan,
struct nvkm_object *object, u32 handle)
{
return nvkm_ramht_insert(chan->disp->ramht, object,
chan->chid.user, -9, handle,
chan->chid.user << 27 | 0x00000001);
}
void
gf119_disp_dmac_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* deactivate channel */
nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00001010, 0x00001000);
nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "ch %d fini: %08x\n", user,
nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
}
chan->suspend_put = nvkm_rd32(device, 0x640000 + (ctrl * 0x1000));
}
static int
gf119_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610494 + (ctrl * 0x0010), chan->push);
nvkm_wr32(device, 0x610498 + (ctrl * 0x0010), 0x00010000);
nvkm_wr32(device, 0x61049c + (ctrl * 0x0010), 0x00000001);
nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), chan->suspend_put);
nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "ch %d init: %08x\n", user,
nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
gf119_disp_dmac_func = {
.init = gf119_disp_dmac_init,
.fini = gf119_disp_dmac_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
/*
* Copyright 2016 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.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
#include <subdev/timer.h>
static int
gp102_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x611494 + (ctrl * 0x0010), chan->push);
nvkm_wr32(device, 0x611498 + (ctrl * 0x0010), 0x00010000);
nvkm_wr32(device, 0x61149c + (ctrl * 0x0010), 0x00000001);
nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), chan->suspend_put);
nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "ch %d init: %08x\n", user,
nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
gp102_disp_dmac_func = {
.init = gp102_disp_dmac_init,
.fini = gf119_disp_dmac_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
/*
* 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 "channv50.h"
#include <core/ramht.h>
#include <subdev/timer.h>
static int
gv100_disp_dmac_idle(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 soff = (chan->chid.ctrl - 1) * 0x04;
nvkm_msec(device, 2000,
u32 stat = nvkm_rd32(device, 0x610664 + soff);
if ((stat & 0x000f0000) == 0x00040000)
return 0;
);
return -EBUSY;
}
int
gv100_disp_dmac_bind(struct nv50_disp_chan *chan,
struct nvkm_object *object, u32 handle)
{
return nvkm_ramht_insert(chan->disp->ramht, object,
chan->chid.user, -9, handle,
chan->chid.user << 25 | 0x00000040);
}
void
gv100_disp_dmac_fini(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u32 uoff = (chan->chid.ctrl - 1) * 0x1000;
const u32 coff = chan->chid.ctrl * 0x04;
nvkm_mask(device, 0x6104e0 + coff, 0x00000010, 0x00000000);
gv100_disp_dmac_idle(chan);
nvkm_mask(device, 0x6104e0 + coff, 0x00000002, 0x00000000);
chan->suspend_put = nvkm_rd32(device, 0x690000 + uoff);
}
int
gv100_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
const u32 uoff = (chan->chid.ctrl - 1) * 0x1000;
const u32 poff = chan->chid.ctrl * 0x10;
const u32 coff = chan->chid.ctrl * 0x04;
nvkm_wr32(device, 0x610b24 + poff, lower_32_bits(chan->push));
nvkm_wr32(device, 0x610b20 + poff, upper_32_bits(chan->push));
nvkm_wr32(device, 0x610b28 + poff, 0x00000001);
nvkm_wr32(device, 0x610b2c + poff, 0x00000040);
nvkm_mask(device, 0x6104e0 + coff, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x690000 + uoff, chan->suspend_put);
nvkm_wr32(device, 0x6104e0 + coff, 0x00000013);
return gv100_disp_dmac_idle(chan);
}
/*
* Copyright 2012 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.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <core/client.h>
#include <core/ramht.h>
#include <subdev/fb.h>
#include <subdev/mmu.h>
#include <subdev/timer.h>
#include <engine/dma.h>
int
nv50_disp_dmac_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nvkm_disp *disp, int chid, int head, u64 push,
const struct nvkm_oclass *oclass,
struct nvkm_object **pobject)
{
struct nvkm_client *client = oclass->client;
struct nv50_disp_chan *chan;
int ret;
ret = nv50_disp_chan_new_(func, mthd, disp, chid, chid, head, oclass,
pobject);
chan = nv50_disp_chan(*pobject);
if (ret)
return ret;
chan->memory = nvkm_umem_search(client, push);
if (IS_ERR(chan->memory))
return PTR_ERR(chan->memory);
if (nvkm_memory_size(chan->memory) < 0x1000)
return -EINVAL;
switch (nvkm_memory_target(chan->memory)) {
case NVKM_MEM_TARGET_VRAM: chan->push = 0x00000001; break;
case NVKM_MEM_TARGET_NCOH: chan->push = 0x00000002; break;
case NVKM_MEM_TARGET_HOST: chan->push = 0x00000003; break;
default:
return -EINVAL;
}
chan->push |= nvkm_memory_addr(chan->memory) >> 8;
return 0;
}
int
nv50_disp_dmac_bind(struct nv50_disp_chan *chan,
struct nvkm_object *object, u32 handle)
{
return nvkm_ramht_insert(chan->disp->ramht, object,
chan->chid.user, -10, handle,
chan->chid.user << 28 |
chan->chid.user);
}
static void
nv50_disp_dmac_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* deactivate channel */
nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00001010, 0x00001000);
nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "ch %d fini timeout, %08x\n", user,
nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
}
chan->suspend_put = nvkm_rd32(device, 0x640000 + (ctrl * 0x1000));
}
static int
nv50_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610204 + (ctrl * 0x0010), chan->push);
nvkm_wr32(device, 0x610208 + (ctrl * 0x0010), 0x00010000);
nvkm_wr32(device, 0x61020c + (ctrl * 0x0010), ctrl);
nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), chan->suspend_put);
nvkm_wr32(device, 0x610200 + (ctrl * 0x0010), 0x00000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "ch %d init timeout, %08x\n", user,
nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
nv50_disp_dmac_func = {
.init = nv50_disp_dmac_init,
.fini = nv50_disp_dmac_fini,
.intr = nv50_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = nv50_disp_dmac_bind,
};
...@@ -22,16 +22,284 @@ ...@@ -22,16 +22,284 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "priv.h" #include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h"
#include <nvif/class.h> #include <nvif/class.h>
void
g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
0x1f000000 /* ??? */ |
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
struct packed_hdmi_infoframe avi_infoframe;
struct packed_hdmi_infoframe vendor_infoframe;
pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header);
nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x616534 + hoff, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x616538 + hoff, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001);
}
/* Audio InfoFrame */
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x616508 + hoff, 0x000a0184);
nvkm_wr32(device, 0x61650c + hoff, 0x00000071);
nvkm_wr32(device, 0x616510 + hoff, 0x00000000);
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001);
/* Vendor InfoFrame */
nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000);
if (vendor_size) {
nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header);
nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high);
/* Is there a second (or up to fourth?) set of subpack registers here? */
/* nvkm_wr32(device, 0x616550 + hoff, vendor_infoframe->subpack1_low); */
/* nvkm_wr32(device, 0x616554 + hoff, vendor_infoframe->subpack1_high); */
nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001);
}
nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
/* ??? */
nvkm_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
nvkm_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
nvkm_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
/* HDMI_CTRL */
nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
}
static const struct nvkm_ior_func
g84_sor = {
.state = nv50_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
.hdmi = {
.ctrl = g84_sor_hdmi_ctrl,
},
};
int
g84_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&g84_sor, disp, SOR, id);
}
static const struct nvkm_disp_mthd_list
g84_disp_ovly_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x6109a0 },
{ 0x0088, 0x6109c0 },
{ 0x008c, 0x6109c8 },
{ 0x0090, 0x6109b4 },
{ 0x0094, 0x610970 },
{ 0x00a0, 0x610998 },
{ 0x00a4, 0x610964 },
{ 0x00c0, 0x610958 },
{ 0x00e0, 0x6109a8 },
{ 0x00e4, 0x6109d0 },
{ 0x00e8, 0x6109d8 },
{ 0x0100, 0x61094c },
{ 0x0104, 0x610984 },
{ 0x0108, 0x61098c },
{ 0x0800, 0x6109f8 },
{ 0x0808, 0x610a08 },
{ 0x080c, 0x610a10 },
{ 0x0810, 0x610a00 },
{}
}
};
static const struct nvkm_disp_chan_mthd
g84_disp_ovly_mthd = {
.name = "Overlay",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &g84_disp_ovly_mthd_base },
{}
}
};
int
g84_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_ovly_new_(&nv50_disp_dmac_func, &g84_disp_ovly_mthd,
disp, 3, oclass, argv, argc, pobject);
}
static const struct nvkm_disp_mthd_list
g84_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x0008c4 },
{ 0x0088, 0x0008d0 },
{ 0x008c, 0x0008dc },
{ 0x0090, 0x0008e4 },
{ 0x0094, 0x610884 },
{ 0x00a0, 0x6108a0 },
{ 0x00a4, 0x610878 },
{ 0x00c0, 0x61086c },
{ 0x00c4, 0x610800 },
{ 0x00c8, 0x61080c },
{ 0x00cc, 0x610818 },
{ 0x00e0, 0x610858 },
{ 0x00e4, 0x610860 },
{ 0x00e8, 0x6108ac },
{ 0x00ec, 0x6108b4 },
{ 0x00fc, 0x610824 },
{ 0x0100, 0x610894 },
{ 0x0104, 0x61082c },
{ 0x0110, 0x6108bc },
{ 0x0114, 0x61088c },
{}
}
};
static const struct nvkm_disp_chan_mthd
g84_disp_base_mthd = {
.name = "Base",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &g84_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_base_mthd_image },
{}
}
};
int
g84_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&nv50_disp_dmac_func, &g84_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
const struct nvkm_disp_mthd_list
g84_disp_core_mthd_dac = {
.mthd = 0x0080,
.addr = 0x000008,
.data = {
{ 0x0400, 0x610b58 },
{ 0x0404, 0x610bdc },
{ 0x0420, 0x610bc4 },
{}
}
};
const struct nvkm_disp_mthd_list
g84_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000540,
.data = {
{ 0x0800, 0x610ad8 },
{ 0x0804, 0x610ad0 },
{ 0x0808, 0x610a48 },
{ 0x080c, 0x610a78 },
{ 0x0810, 0x610ac0 },
{ 0x0814, 0x610af8 },
{ 0x0818, 0x610b00 },
{ 0x081c, 0x610ae8 },
{ 0x0820, 0x610af0 },
{ 0x0824, 0x610b08 },
{ 0x0828, 0x610b10 },
{ 0x082c, 0x610a68 },
{ 0x0830, 0x610a60 },
{ 0x0834, 0x000000 },
{ 0x0838, 0x610a40 },
{ 0x0840, 0x610a24 },
{ 0x0844, 0x610a2c },
{ 0x0848, 0x610aa8 },
{ 0x084c, 0x610ab0 },
{ 0x085c, 0x610c5c },
{ 0x0860, 0x610a84 },
{ 0x0864, 0x610a90 },
{ 0x0868, 0x610b18 },
{ 0x086c, 0x610b20 },
{ 0x0870, 0x610ac8 },
{ 0x0874, 0x610a38 },
{ 0x0878, 0x610c50 },
{ 0x0880, 0x610a58 },
{ 0x0884, 0x610a9c },
{ 0x089c, 0x610c68 },
{ 0x08a0, 0x610a70 },
{ 0x08a4, 0x610a50 },
{ 0x08a8, 0x610ae0 },
{ 0x08c0, 0x610b28 },
{ 0x08c4, 0x610b30 },
{ 0x08c8, 0x610b40 },
{ 0x08d4, 0x610b38 },
{ 0x08d8, 0x610b48 },
{ 0x08dc, 0x610b50 },
{ 0x0900, 0x610a18 },
{ 0x0904, 0x610ab8 },
{ 0x0910, 0x610c70 },
{ 0x0914, 0x610c78 },
{}
}
};
const struct nvkm_disp_chan_mthd
g84_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
int
g84_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &g84_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
static const struct nvkm_disp_func static const struct nvkm_disp_func
g84_disp = { g84_disp = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit,
.init = nv50_disp_init, .init = nv50_disp_init,
.fini = nv50_disp_fini, .fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
......
...@@ -22,16 +22,331 @@ ...@@ -22,16 +22,331 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "priv.h" #include "priv.h"
#include "chan.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h"
#include <subdev/timer.h>
#include <nvif/class.h> #include <nvif/class.h>
void
g94_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
nvkm_mask(device, 0x61c128 + loff, 0x0000003f, watermark);
}
void
g94_sor_dp_activesym(struct nvkm_ior *sor, int head,
u8 TU, u8 VTUa, u8 VTUf, u8 VTUi)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
nvkm_mask(device, 0x61c10c + loff, 0x000001fc, TU << 2);
nvkm_mask(device, 0x61c128 + loff, 0x010f7f00, VTUa << 24 | VTUf << 16 | VTUi << 8);
}
void
g94_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, h);
nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, v);
}
void
g94_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
const u32 shift = sor->func->dp.lanes[ln] * 8;
u32 data[3];
data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nvkm_rd32(device, 0x61c130 + loff);
if ((data[2] & 0x0000ff00) < (pu << 8) || ln == 0)
data[2] = (data[2] & ~0x0000ff00) | (pu << 8);
nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
nvkm_wr32(device, 0x61c130 + loff, data[2]);
}
void
g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
u32 data;
switch (pattern) {
case 0: data = 0x00001000; break;
case 1: data = 0x01000000; break;
case 2: data = 0x02000000; break;
default:
WARN_ON(1);
return;
}
nvkm_mask(device, 0x61c10c + loff, 0x0f001000, data);
}
void
g94_sor_dp_power(struct nvkm_ior *sor, int nr)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
const u32 loff = nv50_sor_link(sor);
u32 mask = 0, i;
for (i = 0; i < nr; i++)
mask |= 1 << sor->func->dp.lanes[i];
nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask);
nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000))
break;
);
}
int
g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
const u32 loff = nv50_sor_link(sor);
u32 dpctrl = 0x00000000;
u32 clksor = 0x00000000;
dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
if (sor->dp.ef)
dpctrl |= 0x00004000;
if (sor->dp.bw > 0x06)
clksor |= 0x00040000;
nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor);
nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl);
return 0;
}
static bool
g94_sor_war_needed(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
if (sor->asy.proto == TMDS) {
switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) {
case 0x00000000:
case 0x00030000:
return true;
default:
break;
}
}
return false;
}
static void
g94_sor_war_update_sppll1(struct nvkm_disp *disp)
{
struct nvkm_device *device = disp->engine.subdev.device;
struct nvkm_ior *ior;
bool used = false;
u32 clksor;
list_for_each_entry(ior, &disp->iors, head) {
if (ior->type != SOR)
continue;
clksor = nvkm_rd32(device, 0x614300 + nv50_ior_base(ior));
switch (clksor & 0x03000000) {
case 0x02000000:
case 0x03000000:
used = true;
break;
default:
break;
}
}
if (used)
return;
nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000);
}
static void
g94_sor_war_3(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
u32 sorpwr;
if (!g94_sor_war_needed(sor))
return;
sorpwr = nvkm_rd32(device, 0x61c004 + soff);
if (sorpwr & 0x00000001) {
u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
u32 pd_pc = (seqctl & 0x00000f00) >> 8;
u32 pu_pc = seqctl & 0x0000000f;
nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
break;
);
nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
break;
);
nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000);
nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000);
}
nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000);
if (sorpwr & 0x00000001)
nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001);
g94_sor_war_update_sppll1(sor->disp);
}
static void
g94_sor_war_2(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
if (!g94_sor_war_needed(sor))
return;
nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000);
nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000);
nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001);
nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000);
nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000);
nvkm_usec(device, 400, NVKM_DELAY);
nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000);
nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000);
if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) {
u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
u32 pu_pc = seqctl & 0x0000000f;
nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000);
}
}
void
g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 coff = sor->id * 8 + (state == &sor->arm) * 4;
u32 ctrl = nvkm_rd32(device, 0x610794 + coff);
state->proto_evo = (ctrl & 0x00000f00) >> 8;
switch (state->proto_evo) {
case 0: state->proto = LVDS; state->link = 1; break;
case 1: state->proto = TMDS; state->link = 1; break;
case 2: state->proto = TMDS; state->link = 2; break;
case 5: state->proto = TMDS; state->link = 3; break;
case 8: state->proto = DP; state->link = 1; break;
case 9: state->proto = DP; state->link = 2; break;
default:
state->proto = UNKNOWN;
break;
}
state->head = ctrl & 0x00000003;
nv50_pior_depth(sor, state, ctrl);
}
static const struct nvkm_ior_func
g94_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
.war_2 = g94_sor_war_2,
.war_3 = g94_sor_war_3,
.dp = {
.lanes = { 2, 1, 0, 3},
.links = g94_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = g94_sor_dp_pattern,
.drive = g94_sor_dp_drive,
.audio_sym = g94_sor_dp_audio_sym,
.activesym = g94_sor_dp_activesym,
.watermark = g94_sor_dp_watermark,
},
};
static int
g94_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&g94_sor, disp, SOR, id);
}
int
g94_sor_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = (nvkm_rd32(device, 0x610184) & 0x0f000000) >> 24;
return 4;
}
static const struct nvkm_disp_mthd_list
g94_disp_core_mthd_sor = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0600, 0x610794 },
{}
}
};
const struct nvkm_disp_chan_mthd
g94_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 4, &g94_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
int
g94_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &g94_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
static const struct nvkm_disp_func static const struct nvkm_disp_func
g94_disp = { g94_disp = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit,
.init = nv50_disp_init, .init = nv50_disp_init,
.fini = nv50_disp_fini, .fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
......
...@@ -20,16 +20,140 @@ ...@@ -20,16 +20,140 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "priv.h" #include "priv.h"
#include "chan.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h"
#include <subdev/timer.h>
#include <nvif/class.h> #include <nvif/class.h>
static int
ga102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
const u32 loff = nv50_sor_link(sor);
u32 dpctrl = 0x00000000;
u32 clksor = 0x00000000;
switch (sor->dp.bw) {
case 0x06: clksor |= 0x00000000; break;
case 0x0a: clksor |= 0x00040000; break;
case 0x14: clksor |= 0x00080000; break;
case 0x1e: clksor |= 0x000c0000; break;
case 0x08: clksor |= 0x00100000; break;
case 0x09: clksor |= 0x00140000; break;
case 0x0c: clksor |= 0x00180000; break;
case 0x10: clksor |= 0x001c0000; break;
default:
WARN_ON(1);
return -EINVAL;
}
dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
if (sor->dp.mst)
dpctrl |= 0x40000000;
if (sor->dp.ef)
dpctrl |= 0x00004000;
nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor);
/*XXX*/
nvkm_msec(device, 40, NVKM_DELAY);
nvkm_mask(device, 0x612300 + soff, 0x00030000, 0x00010000);
nvkm_mask(device, 0x61c10c + loff, 0x00000003, 0x00000001);
nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl);
return 0;
}
static void
ga102_sor_clock(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
u32 div2 = 0;
if (sor->asy.proto == TMDS) {
if (sor->tmds.high_speed)
div2 = 1;
}
nvkm_wr32(device, 0x00ec08 + (sor->id * 0x10), 0x00000000);
nvkm_wr32(device, 0x00ec04 + (sor->id * 0x10), div2);
}
static const struct nvkm_ior_func
ga102_sor_hda = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = ga102_sor_clock,
.hdmi = {
.ctrl = gv100_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = {
.lanes = { 0, 1, 2, 3 },
.links = ga102_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gm200_sor_dp_drive,
.vcpi = tu102_sor_dp_vcpi,
.audio = gv100_sor_dp_audio,
.audio_sym = gv100_sor_dp_audio_sym,
.watermark = gv100_sor_dp_watermark,
},
.hda = {
.hpd = gf119_sor_hda_hpd,
.eld = gf119_sor_hda_eld,
.device_entry = gv100_sor_hda_device_entry,
},
};
static const struct nvkm_ior_func
ga102_sor = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = ga102_sor_clock,
.hdmi = {
.ctrl = gv100_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = {
.lanes = { 0, 1, 2, 3 },
.links = ga102_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gm200_sor_dp_drive,
.vcpi = tu102_sor_dp_vcpi,
.audio = gv100_sor_dp_audio,
.audio_sym = gv100_sor_dp_audio_sym,
.watermark = gv100_sor_dp_watermark,
},
};
static int
ga102_sor_new(struct nvkm_disp *disp, int id)
{
struct nvkm_device *device = disp->engine.subdev.device;
u32 hda = nvkm_rd32(device, 0x08a15c);
if (hda & BIT(id))
return nvkm_ior_new_(&ga102_sor_hda, disp, SOR, id);
return nvkm_ior_new_(&ga102_sor, disp, SOR, id);
}
static const struct nvkm_disp_func static const struct nvkm_disp_func
ga102_disp = { ga102_disp = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit,
.init = tu102_disp_init, .init = tu102_disp_init,
.fini = gv100_disp_fini, .fini = gv100_disp_fini,
.intr = gv100_disp_intr, .intr = gv100_disp_intr,
......
...@@ -22,16 +22,16 @@ ...@@ -22,16 +22,16 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "priv.h" #include "priv.h"
#include "chan.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h"
#include <nvif/class.h> #include <nvif/class.h>
static const struct nvkm_disp_func static const struct nvkm_disp_func
gk110_disp = { gk110_disp = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit,
.init = gf119_disp_init, .init = gf119_disp_init,
.fini = gf119_disp_fini, .fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
......
...@@ -22,16 +22,72 @@ ...@@ -22,16 +22,72 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "priv.h" #include "priv.h"
#include "chan.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h"
#include <nvif/class.h> #include <nvif/class.h>
void
gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
u32 mask = 0x1f1f1f1f, data;
switch (pattern) {
case 0: data = 0x10101010; break;
case 1: data = 0x01010101; break;
case 2: data = 0x02020202; break;
case 3: data = 0x03030303; break;
case 4: data = 0x1b1b1b1b; break;
default:
WARN_ON(1);
return;
}
if (sor->asy.link & 1)
nvkm_mask(device, 0x61c110 + soff, mask, data);
else
nvkm_mask(device, 0x61c12c + soff, mask, data);
}
static const struct nvkm_ior_func
gm107_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
},
.dp = {
.lanes = { 0, 1, 2, 3 },
.links = gf119_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gf119_sor_dp_drive,
.vcpi = gf119_sor_dp_vcpi,
.audio = gf119_sor_dp_audio,
.audio_sym = gf119_sor_dp_audio_sym,
.watermark = gf119_sor_dp_watermark,
},
.hda = {
.hpd = gf119_sor_hda_hpd,
.eld = gf119_sor_hda_eld,
.device_entry = gf119_sor_hda_device_entry,
},
};
static int
gm107_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&gm107_sor, disp, SOR, id);
}
static const struct nvkm_disp_func static const struct nvkm_disp_func
gm107_disp = { gm107_disp = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit,
.init = gf119_disp_init, .init = gf119_disp_init,
.fini = gf119_disp_fini, .fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
......
...@@ -22,16 +22,169 @@ ...@@ -22,16 +22,169 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "priv.h" #include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h" #include "outp.h"
#include <nvif/class.h> #include <nvif/class.h>
void
gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
const u32 shift = sor->func->dp.lanes[ln] * 8;
u32 data[4];
pu &= 0x0f;
data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nvkm_rd32(device, 0x61c130 + loff);
if ((data[2] & 0x00000f00) < (pu << 8) || ln == 0)
data[2] = (data[2] & ~0x00000f00) | (pu << 8);
nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
nvkm_wr32(device, 0x61c130 + loff, data[2]);
data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift));
}
void
gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(ior);
const u32 ctrl = scdc & 0x3;
nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
ior->tmds.high_speed = !!(scdc & 0x2);
}
void
gm200_sor_route_set(struct nvkm_outp *outp, struct nvkm_ior *ior)
{
struct nvkm_device *device = outp->disp->engine.subdev.device;
const u32 moff = __ffs(outp->info.or) * 0x100;
const u32 sor = ior ? ior->id + 1 : 0;
u32 link = ior ? (ior->asy.link == 2) : 0;
if (outp->info.sorconf.link & 1) {
nvkm_mask(device, 0x612308 + moff, 0x0000001f, link << 4 | sor);
link++;
}
if (outp->info.sorconf.link & 2)
nvkm_mask(device, 0x612388 + moff, 0x0000001f, link << 4 | sor);
}
int
gm200_sor_route_get(struct nvkm_outp *outp, int *link)
{
struct nvkm_device *device = outp->disp->engine.subdev.device;
const int sublinks = outp->info.sorconf.link;
int lnk[2], sor[2], m, s;
for (*link = 0, m = __ffs(outp->info.or) * 2, s = 0; s < 2; m++, s++) {
if (sublinks & BIT(s)) {
u32 data = nvkm_rd32(device, 0x612308 + (m * 0x80));
lnk[s] = (data & 0x00000010) >> 4;
sor[s] = (data & 0x0000000f);
if (!sor[s])
return -1;
*link |= lnk[s];
}
}
if (sublinks == 3) {
if (sor[0] != sor[1] || WARN_ON(lnk[0] || !lnk[1]))
return -1;
}
return ((sublinks & 1) ? sor[0] : sor[1]) - 1;
}
static const struct nvkm_ior_func
gm200_sor_hda = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = {
.lanes = { 0, 1, 2, 3 },
.links = gf119_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gm200_sor_dp_drive,
.vcpi = gf119_sor_dp_vcpi,
.audio = gf119_sor_dp_audio,
.audio_sym = gf119_sor_dp_audio_sym,
.watermark = gf119_sor_dp_watermark,
},
.hda = {
.hpd = gf119_sor_hda_hpd,
.eld = gf119_sor_hda_eld,
.device_entry = gf119_sor_hda_device_entry,
},
};
static const struct nvkm_ior_func
gm200_sor = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = {
.lanes = { 0, 1, 2, 3 },
.links = gf119_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gm200_sor_dp_drive,
.vcpi = gf119_sor_dp_vcpi,
.audio = gf119_sor_dp_audio,
.audio_sym = gf119_sor_dp_audio_sym,
.watermark = gf119_sor_dp_watermark,
},
};
static int
gm200_sor_new(struct nvkm_disp *disp, int id)
{
struct nvkm_device *device = disp->engine.subdev.device;
u32 hda;
if (!((hda = nvkm_rd32(device, 0x08a15c)) & 0x40000000))
hda = nvkm_rd32(device, 0x101034);
if (hda & BIT(id))
return nvkm_ior_new_(&gm200_sor_hda, disp, SOR, id);
return nvkm_ior_new_(&gm200_sor, disp, SOR, id);
}
static const struct nvkm_disp_func static const struct nvkm_disp_func
gm200_disp = { gm200_disp = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit,
.init = gf119_disp_init, .init = gf119_disp_init,
.fini = gf119_disp_fini, .fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册