summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/engine
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:35:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:39:31 +0000
commit85c675d0d09a45a135bddd15d7b385f8758c32fb (patch)
tree76267dbc9b9a130337be3640948fe397b04ac629 /drivers/gpu/drm/nouveau/nvkm/engine
parentAdding upstream version 6.6.15. (diff)
downloadlinux-85c675d0d09a45a135bddd15d7b385f8758c32fb.tar.xz
linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.zip
Adding upstream version 6.7.7.upstream/6.7.7
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/r535.c108
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c190
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/user.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ad102.c52
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c158
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c362
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c17
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h17
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c184
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c147
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/r535.c1714
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c98
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c460
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/falcon.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c55
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c665
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ad102.c46
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/r535.c508
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ad102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga100.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/r535.c110
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/tu102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/Kbuild5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ad102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/base.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ga102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/priv.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/r535.c110
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/tu102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/Kbuild5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ad102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ga100.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/priv.h8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/r535.c107
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ofa/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ofa/ad102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga100.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga102.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ofa/priv.h8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ofa/r535.c107
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/r535.c54
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c8
93 files changed, 5422 insertions, 693 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
index c6dfed18f3..bfaaff645a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
@@ -17,6 +17,8 @@ include $(src)/nvkm/engine/msppp/Kbuild
include $(src)/nvkm/engine/msvld/Kbuild
include $(src)/nvkm/engine/nvenc/Kbuild
include $(src)/nvkm/engine/nvdec/Kbuild
+include $(src)/nvkm/engine/nvjpg/Kbuild
+include $(src)/nvkm/engine/ofa/Kbuild
include $(src)/nvkm/engine/pm/Kbuild
include $(src)/nvkm/engine/sec/Kbuild
include $(src)/nvkm/engine/sec2/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
index 8bf1635ffa..165d61fc5d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
@@ -10,3 +10,5 @@ nvkm-y += nvkm/engine/ce/gv100.o
nvkm-y += nvkm/engine/ce/tu102.o
nvkm-y += nvkm/engine/ce/ga100.o
nvkm-y += nvkm/engine/ce/ga102.o
+
+nvkm-y += nvkm/engine/ce/r535.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c
index 315a69f7fd..9427a592bd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c
@@ -21,6 +21,7 @@
*/
#include "priv.h"
+#include <subdev/gsp.h>
#include <subdev/vfn.h>
#include <nvif/class.h>
@@ -88,5 +89,8 @@ int
ga100_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_engine **pengine)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_ce_new(&ga100_ce, device, type, inst, pengine);
+
return nvkm_engine_new_(&ga100_ce, device, type, inst, true, pengine);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c
index 461b73c7e2..ce56ede7c2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c
@@ -21,6 +21,8 @@
*/
#include "priv.h"
+#include <subdev/gsp.h>
+
#include <nvif/class.h>
static const struct nvkm_engine_func
@@ -41,5 +43,8 @@ int
ga102_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_engine **pengine)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_ce_new(&ga102_ce, device, type, inst, pengine);
+
return nvkm_engine_new_(&ga102_ce, device, type, inst, true, pengine);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
index 0be72c463b..806a76a722 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
@@ -3,6 +3,9 @@
#define __NVKM_CE_PRIV_H__
#include <engine/ce.h>
+int r535_ce_new(const struct nvkm_engine_func *, struct nvkm_device *,
+ enum nvkm_subdev_type, int, struct nvkm_engine **);
+
void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_chan *);
void gk104_ce_intr(struct nvkm_engine *);
void gp100_ce_intr(struct nvkm_engine *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/r535.c
new file mode 100644
index 0000000000..bd0d435dbb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/r535.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <core/object.h>
+#include <subdev/gsp.h>
+#include <engine/fifo.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/class/cl2080_notification.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/class/clc0b5sw.h>
+
+struct r535_ce_obj {
+ struct nvkm_object object;
+ struct nvkm_gsp_object rm;
+};
+
+static void *
+r535_ce_obj_dtor(struct nvkm_object *object)
+{
+ struct r535_ce_obj *obj = container_of(object, typeof(*obj), object);
+
+ nvkm_gsp_rm_free(&obj->rm);
+ return obj;
+}
+
+static const struct nvkm_object_func
+r535_ce_obj = {
+ .dtor = r535_ce_obj_dtor,
+};
+
+static int
+r535_ce_obj_ctor(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_chan *chan = nvkm_uchan_chan(oclass->parent);
+ struct r535_ce_obj *obj;
+ NVC0B5_ALLOCATION_PARAMETERS *args;
+
+ if (!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_ce_obj, oclass, &obj->object);
+ *pobject = &obj->object;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->rm.object, oclass->handle, oclass->base.oclass,
+ sizeof(*args), &obj->rm);
+ if (WARN_ON(IS_ERR(args)))
+ return PTR_ERR(args);
+
+ args->version = 1;
+ args->engineType = NV2080_ENGINE_TYPE_COPY0 + oclass->engine->subdev.inst;
+
+ return nvkm_gsp_rm_alloc_wr(&obj->rm, args);
+}
+
+static void *
+r535_ce_dtor(struct nvkm_engine *engine)
+{
+ kfree(engine->func);
+ return engine;
+}
+
+int
+r535_ce_new(const struct nvkm_engine_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_engine **pengine)
+{
+ struct nvkm_engine_func *rm;
+ int nclass, ret;
+
+ for (nclass = 0; hw->sclass[nclass].oclass; nclass++);
+
+ if (!(rm = kzalloc(sizeof(*rm) + (nclass + 1) * sizeof(rm->sclass[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_ce_dtor;
+ for (int i = 0; i < nclass; i++) {
+ rm->sclass[i].minver = hw->sclass[i].minver;
+ rm->sclass[i].maxver = hw->sclass[i].maxver;
+ rm->sclass[i].oclass = hw->sclass[i].oclass;
+ rm->sclass[i].ctor = r535_ce_obj_ctor;
+ }
+
+ ret = nvkm_engine_new_(rm, device, type, inst, true, pengine);
+ if (ret)
+ kfree(rm);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c
index 9563c01751..7c8647dcb3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c
@@ -21,6 +21,8 @@
*/
#include "priv.h"
+#include <subdev/gsp.h>
+
#include <nvif/class.h>
static const struct nvkm_engine_func
@@ -37,5 +39,8 @@ int
tu102_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_engine **pengine)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_ce_new(&tu102_ce, device, type, inst, pengine);
+
return nvkm_engine_new_(&tu102_ce, device, type, inst, true, pengine);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index 1c81e5b34d..31ed3da32f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -2408,7 +2408,7 @@ nv162_chipset = {
.fb = { 0x00000001, tu102_fb_new },
.fuse = { 0x00000001, gm107_fuse_new },
.gpio = { 0x00000001, gk104_gpio_new },
- .gsp = { 0x00000001, gv100_gsp_new },
+ .gsp = { 0x00000001, tu102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
@@ -2426,8 +2426,8 @@ nv162_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, tu102_fifo_new },
.gr = { 0x00000001, tu102_gr_new },
- .nvdec = { 0x00000001, gm107_nvdec_new },
- .nvenc = { 0x00000001, gm107_nvenc_new },
+ .nvdec = { 0x00000001, tu102_nvdec_new },
+ .nvenc = { 0x00000001, tu102_nvenc_new },
.sec2 = { 0x00000001, tu102_sec2_new },
};
@@ -2443,7 +2443,7 @@ nv164_chipset = {
.fb = { 0x00000001, tu102_fb_new },
.fuse = { 0x00000001, gm107_fuse_new },
.gpio = { 0x00000001, gk104_gpio_new },
- .gsp = { 0x00000001, gv100_gsp_new },
+ .gsp = { 0x00000001, tu102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
@@ -2461,8 +2461,8 @@ nv164_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, tu102_fifo_new },
.gr = { 0x00000001, tu102_gr_new },
- .nvdec = { 0x00000003, gm107_nvdec_new },
- .nvenc = { 0x00000001, gm107_nvenc_new },
+ .nvdec = { 0x00000003, tu102_nvdec_new },
+ .nvenc = { 0x00000001, tu102_nvenc_new },
.sec2 = { 0x00000001, tu102_sec2_new },
};
@@ -2478,7 +2478,7 @@ nv166_chipset = {
.fb = { 0x00000001, tu102_fb_new },
.fuse = { 0x00000001, gm107_fuse_new },
.gpio = { 0x00000001, gk104_gpio_new },
- .gsp = { 0x00000001, gv100_gsp_new },
+ .gsp = { 0x00000001, tu102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
@@ -2496,8 +2496,8 @@ nv166_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, tu102_fifo_new },
.gr = { 0x00000001, tu102_gr_new },
- .nvdec = { 0x00000007, gm107_nvdec_new },
- .nvenc = { 0x00000001, gm107_nvenc_new },
+ .nvdec = { 0x00000007, tu102_nvdec_new },
+ .nvenc = { 0x00000001, tu102_nvenc_new },
.sec2 = { 0x00000001, tu102_sec2_new },
};
@@ -2513,7 +2513,7 @@ nv167_chipset = {
.fb = { 0x00000001, tu102_fb_new },
.fuse = { 0x00000001, gm107_fuse_new },
.gpio = { 0x00000001, gk104_gpio_new },
- .gsp = { 0x00000001, gv100_gsp_new },
+ .gsp = { 0x00000001, tu116_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
@@ -2531,8 +2531,8 @@ nv167_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, tu102_fifo_new },
.gr = { 0x00000001, tu102_gr_new },
- .nvdec = { 0x00000001, gm107_nvdec_new },
- .nvenc = { 0x00000001, gm107_nvenc_new },
+ .nvdec = { 0x00000001, tu102_nvdec_new },
+ .nvenc = { 0x00000001, tu102_nvenc_new },
.sec2 = { 0x00000001, tu102_sec2_new },
};
@@ -2548,7 +2548,7 @@ nv168_chipset = {
.fb = { 0x00000001, tu102_fb_new },
.fuse = { 0x00000001, gm107_fuse_new },
.gpio = { 0x00000001, gk104_gpio_new },
- .gsp = { 0x00000001, gv100_gsp_new },
+ .gsp = { 0x00000001, tu116_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
@@ -2566,8 +2566,8 @@ nv168_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, tu102_fifo_new },
.gr = { 0x00000001, tu102_gr_new },
- .nvdec = { 0x00000001, gm107_nvdec_new },
- .nvenc = { 0x00000001, gm107_nvenc_new },
+ .nvdec = { 0x00000001, tu102_nvdec_new },
+ .nvenc = { 0x00000001, tu102_nvenc_new },
.sec2 = { 0x00000001, tu102_sec2_new },
};
@@ -2580,6 +2580,7 @@ nv170_chipset = {
.fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga100_fb_new },
.gpio = { 0x00000001, gk104_gpio_new },
+ .gsp = { 0x00000001, ga100_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.mc = { 0x00000001, ga100_mc_new },
@@ -2591,6 +2592,9 @@ nv170_chipset = {
.vfn = { 0x00000001, ga100_vfn_new },
.ce = { 0x000003ff, ga100_ce_new },
.fifo = { 0x00000001, ga100_fifo_new },
+ .nvdec = { 0x0000001f, ga100_nvdec_new },
+ .nvjpg = { 0x00000001, ga100_nvjpg_new },
+ .ofa = { 0x00000001, ga100_ofa_new },
};
static const struct nvkm_device_chip
@@ -2619,7 +2623,9 @@ nv172_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
.gr = { 0x00000001, ga102_gr_new },
- .nvdec = { 0x00000001, ga102_nvdec_new },
+ .nvdec = { 0x00000003, ga102_nvdec_new },
+ .nvenc = { 0x00000001, ga102_nvenc_new },
+ .ofa = { 0x00000001, ga102_ofa_new },
.sec2 = { 0x00000001, ga102_sec2_new },
};
@@ -2649,7 +2655,9 @@ nv173_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
.gr = { 0x00000001, ga102_gr_new },
- .nvdec = { 0x00000001, ga102_nvdec_new },
+ .nvdec = { 0x00000003, ga102_nvdec_new },
+ .nvenc = { 0x00000001, ga102_nvenc_new },
+ .ofa = { 0x00000001, ga102_ofa_new },
.sec2 = { 0x00000001, ga102_sec2_new },
};
@@ -2679,7 +2687,9 @@ nv174_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
.gr = { 0x00000001, ga102_gr_new },
- .nvdec = { 0x00000001, ga102_nvdec_new },
+ .nvdec = { 0x00000003, ga102_nvdec_new },
+ .nvenc = { 0x00000001, ga102_nvenc_new },
+ .ofa = { 0x00000001, ga102_ofa_new },
.sec2 = { 0x00000001, ga102_sec2_new },
};
@@ -2709,7 +2719,9 @@ nv176_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
.gr = { 0x00000001, ga102_gr_new },
- .nvdec = { 0x00000001, ga102_nvdec_new },
+ .nvdec = { 0x00000003, ga102_nvdec_new },
+ .nvenc = { 0x00000001, ga102_nvenc_new },
+ .ofa = { 0x00000001, ga102_ofa_new },
.sec2 = { 0x00000001, ga102_sec2_new },
};
@@ -2739,7 +2751,139 @@ nv177_chipset = {
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
.gr = { 0x00000001, ga102_gr_new },
- .nvdec = { 0x00000001, ga102_nvdec_new },
+ .nvdec = { 0x00000003, ga102_nvdec_new },
+ .nvenc = { 0x00000001, ga102_nvenc_new },
+ .ofa = { 0x00000001, ga102_ofa_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
+};
+
+static const struct nvkm_device_chip
+nv192_chipset = {
+ .name = "AD102",
+ .bar = { 0x00000001, tu102_bar_new },
+ .bios = { 0x00000001, nvkm_bios_new },
+ .devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
+ .fb = { 0x00000001, ga102_fb_new },
+ .gsp = { 0x00000001, ad102_gsp_new },
+ .imem = { 0x00000001, nv50_instmem_new },
+ .mmu = { 0x00000001, tu102_mmu_new },
+ .pci = { 0x00000001, gp100_pci_new },
+ .timer = { 0x00000001, gk20a_timer_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
+ .disp = { 0x00000001, ad102_disp_new },
+ .dma = { 0x00000001, gv100_dma_new },
+ .fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ad102_gr_new },
+ .nvdec = { 0x0000000f, ad102_nvdec_new },
+ .nvenc = { 0x00000007, ad102_nvenc_new },
+ .nvjpg = { 0x0000000f, ad102_nvjpg_new },
+ .ofa = { 0x00000001, ad102_ofa_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
+};
+
+static const struct nvkm_device_chip
+nv193_chipset = {
+ .name = "AD103",
+ .bar = { 0x00000001, tu102_bar_new },
+ .bios = { 0x00000001, nvkm_bios_new },
+ .devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
+ .fb = { 0x00000001, ga102_fb_new },
+ .gsp = { 0x00000001, ad102_gsp_new },
+ .imem = { 0x00000001, nv50_instmem_new },
+ .mmu = { 0x00000001, tu102_mmu_new },
+ .pci = { 0x00000001, gp100_pci_new },
+ .timer = { 0x00000001, gk20a_timer_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
+ .disp = { 0x00000001, ad102_disp_new },
+ .dma = { 0x00000001, gv100_dma_new },
+ .fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ad102_gr_new },
+ .nvdec = { 0x0000000f, ad102_nvdec_new },
+ .nvenc = { 0x00000007, ad102_nvenc_new },
+ .nvjpg = { 0x0000000f, ad102_nvjpg_new },
+ .ofa = { 0x00000001, ad102_ofa_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
+};
+
+static const struct nvkm_device_chip
+nv194_chipset = {
+ .name = "AD104",
+ .bar = { 0x00000001, tu102_bar_new },
+ .bios = { 0x00000001, nvkm_bios_new },
+ .devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
+ .fb = { 0x00000001, ga102_fb_new },
+ .gsp = { 0x00000001, ad102_gsp_new },
+ .imem = { 0x00000001, nv50_instmem_new },
+ .mmu = { 0x00000001, tu102_mmu_new },
+ .pci = { 0x00000001, gp100_pci_new },
+ .timer = { 0x00000001, gk20a_timer_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
+ .disp = { 0x00000001, ad102_disp_new },
+ .dma = { 0x00000001, gv100_dma_new },
+ .fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ad102_gr_new },
+ .nvdec = { 0x0000000f, ad102_nvdec_new },
+ .nvenc = { 0x00000007, ad102_nvenc_new },
+ .nvjpg = { 0x0000000f, ad102_nvjpg_new },
+ .ofa = { 0x00000001, ad102_ofa_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
+};
+
+static const struct nvkm_device_chip
+nv196_chipset = {
+ .name = "AD106",
+ .bar = { 0x00000001, tu102_bar_new },
+ .bios = { 0x00000001, nvkm_bios_new },
+ .devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
+ .fb = { 0x00000001, ga102_fb_new },
+ .gsp = { 0x00000001, ad102_gsp_new },
+ .imem = { 0x00000001, nv50_instmem_new },
+ .mmu = { 0x00000001, tu102_mmu_new },
+ .pci = { 0x00000001, gp100_pci_new },
+ .timer = { 0x00000001, gk20a_timer_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
+ .disp = { 0x00000001, ad102_disp_new },
+ .dma = { 0x00000001, gv100_dma_new },
+ .fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ad102_gr_new },
+ .nvdec = { 0x0000000f, ad102_nvdec_new },
+ .nvenc = { 0x00000007, ad102_nvenc_new },
+ .nvjpg = { 0x0000000f, ad102_nvjpg_new },
+ .ofa = { 0x00000001, ad102_ofa_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
+};
+
+static const struct nvkm_device_chip
+nv197_chipset = {
+ .name = "AD107",
+ .bar = { 0x00000001, tu102_bar_new },
+ .bios = { 0x00000001, nvkm_bios_new },
+ .devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
+ .fb = { 0x00000001, ga102_fb_new },
+ .gsp = { 0x00000001, ad102_gsp_new },
+ .imem = { 0x00000001, nv50_instmem_new },
+ .mmu = { 0x00000001, tu102_mmu_new },
+ .pci = { 0x00000001, gp100_pci_new },
+ .timer = { 0x00000001, gk20a_timer_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
+ .disp = { 0x00000001, ad102_disp_new },
+ .dma = { 0x00000001, gv100_dma_new },
+ .fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ad102_gr_new },
+ .nvdec = { 0x0000000f, ad102_nvdec_new },
+ .nvenc = { 0x00000007, ad102_nvenc_new },
+ .nvjpg = { 0x0000000f, ad102_nvjpg_new },
+ .ofa = { 0x00000001, ad102_ofa_new },
.sec2 = { 0x00000001, ga102_sec2_new },
};
@@ -3061,6 +3205,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x140: device->card_type = GV100; break;
case 0x160: device->card_type = TU100; break;
case 0x170: device->card_type = GA100; break;
+ case 0x190: device->card_type = AD100; break;
default:
break;
}
@@ -3163,6 +3308,11 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x174: device->chip = &nv174_chipset; break;
case 0x176: device->chip = &nv176_chipset; break;
case 0x177: device->chip = &nv177_chipset; break;
+ case 0x192: device->chip = &nv192_chipset; break;
+ case 0x193: device->chip = &nv193_chipset; break;
+ case 0x194: device->chip = &nv194_chipset; break;
+ case 0x196: device->chip = &nv196_chipset; break;
+ case 0x197: device->chip = &nv197_chipset; break;
default:
if (nvkm_boolopt(device->cfgopt, "NvEnableUnsupportedChipsets", false)) {
switch (device->chipset) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
index 24faaac158..bf3176bec1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
@@ -43,6 +43,8 @@
#include <engine/msvld.h>
#include <engine/nvenc.h>
#include <engine/nvdec.h>
+#include <engine/nvjpg.h>
+#include <engine/ofa.h>
#include <engine/pm.h>
#include <engine/sec.h>
#include <engine/sec2.h>
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
index 9b39ec3416..7fd4800a87 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
@@ -147,6 +147,7 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
case GV100: args->v0.family = NV_DEVICE_INFO_V0_VOLTA; break;
case TU100: args->v0.family = NV_DEVICE_INFO_V0_TURING; break;
case GA100: args->v0.family = NV_DEVICE_INFO_V0_AMPERE; break;
+ case AD100: args->v0.family = NV_DEVICE_INFO_V0_ADA; break;
default:
args->v0.family = 0;
break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
index e1aecd3fe9..e346e924fe 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -27,6 +27,9 @@ nvkm-y += nvkm/engine/disp/gp102.o
nvkm-y += nvkm/engine/disp/gv100.o
nvkm-y += nvkm/engine/disp/tu102.o
nvkm-y += nvkm/engine/disp/ga102.o
+nvkm-y += nvkm/engine/disp/ad102.o
+
+nvkm-y += nvkm/engine/disp/r535.o
nvkm-y += nvkm/engine/disp/udisp.o
nvkm-y += nvkm/engine/disp/uconn.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ad102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ad102.c
new file mode 100644
index 0000000000..7f300a79aa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ad102.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 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 "priv.h"
+#include "chan.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_disp_func
+ad102_disp = {
+ .uevent = &gv100_disp_chan_uevent,
+ .ramht_size = 0x2000,
+ .root = { 0, 0,AD102_DISP },
+ .user = {
+ {{-1,-1,GV100_DISP_CAPS }, gv100_disp_caps_new },
+ {{ 0, 0,GA102_DISP_CURSOR }, nvkm_disp_chan_new, &gv100_disp_curs },
+ {{ 0, 0,GA102_DISP_WINDOW_IMM_CHANNEL_DMA}, nvkm_disp_wndw_new, &gv100_disp_wimm },
+ {{ 0, 0,AD102_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gv100_disp_core },
+ {{ 0, 0,GA102_DISP_WINDOW_CHANNEL_DMA }, nvkm_disp_wndw_new, &gv100_disp_wndw },
+ {}
+ },
+};
+
+int
+ad102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_disp **pdisp)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_disp_new(&ad102_disp, device, type, inst, pdisp);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
index 73104b59f9..b24eb1e560 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -23,15 +23,12 @@
*/
#include "priv.h"
#include "conn.h"
-#include "dp.h"
#include "head.h"
#include "ior.h"
#include "outp.h"
#include <core/client.h>
#include <core/ramht.h>
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
#include <nvif/class.h>
#include <nvif/cl0046.h>
@@ -105,18 +102,14 @@ static int
nvkm_disp_fini(struct nvkm_engine *engine, bool suspend)
{
struct nvkm_disp *disp = nvkm_disp(engine);
- struct nvkm_conn *conn;
struct nvkm_outp *outp;
if (disp->func->fini)
- disp->func->fini(disp);
+ disp->func->fini(disp, suspend);
list_for_each_entry(outp, &disp->outps, head) {
- nvkm_outp_fini(outp);
- }
-
- list_for_each_entry(conn, &disp->conns, head) {
- nvkm_conn_fini(conn);
+ if (outp->func->fini)
+ outp->func->fini(outp);
}
return 0;
@@ -126,16 +119,12 @@ static int
nvkm_disp_init(struct nvkm_engine *engine)
{
struct nvkm_disp *disp = nvkm_disp(engine);
- struct nvkm_conn *conn;
struct nvkm_outp *outp;
struct nvkm_ior *ior;
- list_for_each_entry(conn, &disp->conns, head) {
- nvkm_conn_init(conn);
- }
-
list_for_each_entry(outp, &disp->outps, head) {
- nvkm_outp_init(outp);
+ if (outp->func->init)
+ outp->func->init(outp);
}
if (disp->func->init) {
@@ -148,7 +137,8 @@ nvkm_disp_init(struct nvkm_engine *engine)
* each output resource to 'fully enabled'.
*/
list_for_each_entry(ior, &disp->iors, head) {
- ior->func->power(ior, true, true, true, true, true);
+ if (ior->func->power)
+ ior->func->power(ior, true, true, true, true, true);
}
return 0;
@@ -159,142 +149,15 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
{
struct nvkm_disp *disp = nvkm_disp(engine);
struct nvkm_subdev *subdev = &disp->engine.subdev;
- struct nvkm_bios *bios = subdev->device->bios;
- struct nvkm_outp *outp, *outt, *pair;
- struct nvkm_conn *conn;
struct nvkm_head *head;
- struct nvkm_ior *ior;
- struct nvbios_connE connE;
- struct dcb_output dcbE;
- u8 hpd = 0, ver, hdr;
- u32 data;
int ret, i;
- /* Create output path objects for each VBIOS display path. */
- i = -1;
- while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
- if (ver < 0x40) /* No support for chipsets prior to NV50. */
- break;
- if (dcbE.type == DCB_OUTPUT_UNUSED)
- continue;
- if (dcbE.type == DCB_OUTPUT_EOL)
- break;
- outp = NULL;
-
- switch (dcbE.type) {
- case DCB_OUTPUT_ANALOG:
- case DCB_OUTPUT_TV:
- case DCB_OUTPUT_TMDS:
- case DCB_OUTPUT_LVDS:
- ret = nvkm_outp_new(disp, i, &dcbE, &outp);
- break;
- case DCB_OUTPUT_DP:
- ret = nvkm_dp_new(disp, i, &dcbE, &outp);
- break;
- case DCB_OUTPUT_WFD:
- /* No support for WFD yet. */
- ret = -ENODEV;
- continue;
- default:
- nvkm_warn(subdev, "dcb %d type %d unknown\n",
- i, dcbE.type);
- continue;
- }
-
- if (ret) {
- if (outp) {
- if (ret != -ENODEV)
- OUTP_ERR(outp, "ctor failed: %d", ret);
- else
- OUTP_DBG(outp, "not supported");
- nvkm_outp_del(&outp);
- continue;
- }
- nvkm_error(subdev, "failed to create outp %d\n", i);
- continue;
- }
-
- list_add_tail(&outp->head, &disp->outps);
- hpd = max(hpd, (u8)(dcbE.connector + 1));
- }
-
- /* Create connector objects based on available output paths. */
- list_for_each_entry_safe(outp, outt, &disp->outps, head) {
- /* VBIOS data *should* give us the most useful information. */
- data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
- &connE);
-
- /* No bios connector data... */
- if (!data) {
- /* Heuristic: anything with the same ccb index is
- * considered to be on the same connector, any
- * output path without an associated ccb entry will
- * be put on its own connector.
- */
- int ccb_index = outp->info.i2c_index;
- if (ccb_index != 0xf) {
- list_for_each_entry(pair, &disp->outps, head) {
- if (pair->info.i2c_index == ccb_index) {
- outp->conn = pair->conn;
- break;
- }
- }
- }
-
- /* Connector shared with another output path. */
- if (outp->conn)
- continue;
-
- memset(&connE, 0x00, sizeof(connE));
- connE.type = DCB_CONNECTOR_NONE;
- i = -1;
- } else {
- i = outp->info.connector;
- }
-
- /* Check that we haven't already created this connector. */
- list_for_each_entry(conn, &disp->conns, head) {
- if (conn->index == outp->info.connector) {
- outp->conn = conn;
- break;
- }
- }
-
- if (outp->conn)
- continue;
-
- /* Apparently we need to create a new one! */
- ret = nvkm_conn_new(disp, i, &connE, &outp->conn);
- if (ret) {
- nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret);
- nvkm_conn_del(&outp->conn);
- list_del(&outp->head);
- nvkm_outp_del(&outp);
- continue;
- }
-
- list_add_tail(&outp->conn->head, &disp->conns);
- }
-
if (disp->func->oneinit) {
ret = disp->func->oneinit(disp);
if (ret)
return ret;
}
- /* Enforce identity-mapped SOR assignment for panels, which have
- * certain bits (ie. backlight controls) wired to a specific SOR.
- */
- list_for_each_entry(outp, &disp->outps, head) {
- if (outp->conn->info.type == DCB_CONNECTOR_LVDS ||
- outp->conn->info.type == DCB_CONNECTOR_eDP) {
- ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1);
- if (!WARN_ON(!ior))
- ior->identity = true;
- outp->identity = true;
- }
- }
-
i = 0;
list_for_each_entry(head, &disp->heads, head)
i = max(i, head->id + 1);
@@ -346,6 +209,9 @@ nvkm_disp_dtor(struct nvkm_engine *engine)
nvkm_head_del(&head);
}
+ if (disp->func && disp->func->dtor)
+ disp->func->dtor(disp);
+
return data;
}
@@ -377,8 +243,10 @@ nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device,
spin_lock_init(&disp->client.lock);
ret = nvkm_engine_ctor(&nvkm_disp, device, type, inst, true, &disp->engine);
- if (ret)
+ if (ret) {
+ disp->func = NULL;
return ret;
+ }
if (func->super) {
disp->super.wq = create_singlethread_workqueue("nvkm-disp");
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
index 398336ffb6..0202905101 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
@@ -22,6 +22,10 @@ struct nvkm_disp_chan {
u64 push;
u32 suspend_put;
+
+ struct {
+ struct nvkm_gsp_object object;
+ } rm;
};
int nvkm_disp_core_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
index fbdae11378..ff88a5a525 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
@@ -30,16 +30,6 @@
#include <nvif/event.h>
void
-nvkm_conn_fini(struct nvkm_conn *conn)
-{
-}
-
-void
-nvkm_conn_init(struct nvkm_conn *conn)
-{
-}
-
-void
nvkm_conn_del(struct nvkm_conn **pconn)
{
struct nvkm_conn *conn = *pconn;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
index a0600e72b0..01c3146c70 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
@@ -19,8 +19,6 @@ struct nvkm_conn {
int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *,
struct nvkm_conn **);
void nvkm_conn_del(struct nvkm_conn **);
-void nvkm_conn_init(struct nvkm_conn *);
-void nvkm_conn_fini(struct nvkm_conn *);
#define CONN_MSG(c,l,f,a...) do { \
struct nvkm_conn *_conn = (c); \
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index b8ac66b4a2..a109348bd6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -41,6 +41,40 @@
*/
#define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100)
+static int
+nvkm_dp_mst_id_put(struct nvkm_outp *outp, u32 id)
+{
+ return 0;
+}
+
+static int
+nvkm_dp_mst_id_get(struct nvkm_outp *outp, u32 *pid)
+{
+ *pid = BIT(outp->index);
+ return 0;
+}
+
+static int
+nvkm_dp_aux_xfer(struct nvkm_outp *outp, u8 type, u32 addr, u8 *data, u8 *size)
+{
+ int ret = nvkm_i2c_aux_acquire(outp->dp.aux);
+
+ if (ret)
+ return ret;
+
+ ret = nvkm_i2c_aux_xfer(outp->dp.aux, false, type, addr, data, size);
+ nvkm_i2c_aux_release(outp->dp.aux);
+ return ret;
+}
+
+static int
+nvkm_dp_aux_pwr(struct nvkm_outp *outp, bool pu)
+{
+ outp->dp.enabled = pu;
+ nvkm_dp_enable(outp, outp->dp.enabled);
+ return 0;
+}
+
struct lt_state {
struct nvkm_outp *outp;
@@ -282,31 +316,20 @@ nvkm_dp_train_link(struct nvkm_outp *outp, int rate)
struct lt_state lt = {
.outp = outp,
.pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED,
+ .repeaters = outp->dp.lttprs,
};
- u8 sink[2], data;
+ u8 sink[2];
int ret;
OUTP_DBG(outp, "training %dx%02x", ior->dp.nr, ior->dp.bw);
- /* Select LTTPR non-transparent mode if we have a valid configuration,
- * use transparent mode otherwise.
- */
- if (outp->dp.lttpr[0] >= 0x14) {
- data = DPCD_LTTPR_MODE_TRANSPARENT;
- nvkm_wraux(outp->dp.aux, DPCD_LTTPR_MODE, &data, sizeof(data));
-
- if (outp->dp.lttprs) {
- data = DPCD_LTTPR_MODE_NON_TRANSPARENT;
- nvkm_wraux(outp->dp.aux, DPCD_LTTPR_MODE, &data, sizeof(data));
- lt.repeaters = outp->dp.lttprs;
- }
- }
-
/* Set desired link configuration on the sink. */
sink[0] = (outp->dp.rate[rate].dpcd < 0) ? ior->dp.bw : 0;
sink[1] = ior->dp.nr;
if (ior->dp.ef)
sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
+ if (outp->dp.lt.post_adj)
+ sink[1] |= 0x20;
ret = nvkm_wraux(outp->dp.aux, DPCD_LC00_LINK_BW_SET, sink, 2);
if (ret)
@@ -447,71 +470,58 @@ nvkm_dp_train_init(struct nvkm_outp *outp)
}
static int
-nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
+nvkm_dp_drive(struct nvkm_outp *outp, u8 lanes, u8 pe[4], u8 vs[4])
+{
+ struct lt_state lt = {
+ .outp = outp,
+ .stat[4] = (pe[0] << 2) | (vs[0] << 0) |
+ (pe[1] << 6) | (vs[1] << 4),
+ .stat[5] = (pe[2] << 2) | (vs[2] << 0) |
+ (pe[3] << 6) | (vs[3] << 4),
+ };
+
+ return nvkm_dp_train_drive(&lt, false);
+}
+
+static int
+nvkm_dp_train(struct nvkm_outp *outp, bool retrain)
{
struct nvkm_ior *ior = outp->ior;
- int ret = -EINVAL, nr, rate;
- u8 pwr;
+ int ret, rate;
- /* Retraining link? Skip source configuration, it can mess up the active modeset. */
- if (atomic_read(&outp->dp.lt.done)) {
- for (rate = 0; rate < outp->dp.rates; rate++) {
- if (outp->dp.rate[rate].rate == ior->dp.bw * 27000)
- return nvkm_dp_train_link(outp, ret);
- }
- WARN_ON(1);
- return -EINVAL;
+ for (rate = 0; rate < outp->dp.rates; rate++) {
+ if (outp->dp.rate[rate].rate == (retrain ? ior->dp.bw : outp->dp.lt.bw) * 27000)
+ break;
}
- /* Ensure sink is not in a low-power state. */
- if (!nvkm_rdaux(outp->dp.aux, DPCD_SC00, &pwr, 1)) {
- if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
- pwr &= ~DPCD_SC00_SET_POWER;
- pwr |= DPCD_SC00_SET_POWER_D0;
- nvkm_wraux(outp->dp.aux, DPCD_SC00, &pwr, 1);
- }
+ if (WARN_ON(rate == outp->dp.rates))
+ return -EINVAL;
+
+ /* Retraining link? Skip source configuration, it can mess up the active modeset. */
+ if (retrain) {
+ mutex_lock(&outp->dp.mutex);
+ ret = nvkm_dp_train_link(outp, rate);
+ mutex_unlock(&outp->dp.mutex);
+ return ret;
}
+ mutex_lock(&outp->dp.mutex);
+ OUTP_DBG(outp, "training");
+
ior->dp.mst = outp->dp.lt.mst;
ior->dp.ef = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP;
- ior->dp.nr = 0;
+ ior->dp.bw = outp->dp.lt.bw;
+ ior->dp.nr = outp->dp.lt.nr;
- /* Link training. */
- OUTP_DBG(outp, "training");
nvkm_dp_train_init(outp);
-
- /* Validate and train at configuration requested (if any) on ACQUIRE. */
- if (outp->dp.lt.nr) {
- for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
- for (rate = 0; nr == outp->dp.lt.nr && rate < outp->dp.rates; rate++) {
- if (outp->dp.rate[rate].rate / 27000 == outp->dp.lt.bw) {
- ior->dp.bw = outp->dp.rate[rate].rate / 27000;
- ior->dp.nr = nr;
- ret = nvkm_dp_train_links(outp, rate);
- }
- }
- }
- }
-
- /* Otherwise, loop through all valid link configurations that support the data rate. */
- for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
- for (rate = 0; ret < 0 && rate < outp->dp.rates; rate++) {
- if (outp->dp.rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) {
- /* Program selected link configuration. */
- ior->dp.bw = outp->dp.rate[rate].rate / 27000;
- ior->dp.nr = nr;
- ret = nvkm_dp_train_links(outp, rate);
- }
- }
- }
-
- /* Finish up. */
+ ret = nvkm_dp_train_links(outp, rate);
nvkm_dp_train_fini(outp);
if (ret < 0)
OUTP_ERR(outp, "training failed");
else
OUTP_DBG(outp, "training done");
- atomic_set(&outp->dp.lt.done, 1);
+
+ mutex_unlock(&outp->dp.mutex);
return ret;
}
@@ -529,155 +539,10 @@ nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
static void
nvkm_dp_release(struct nvkm_outp *outp)
{
- /* Prevent link from being retrained if sink sends an IRQ. */
- atomic_set(&outp->dp.lt.done, 0);
outp->ior->dp.nr = 0;
-}
-
-static int
-nvkm_dp_acquire(struct nvkm_outp *outp)
-{
- struct nvkm_ior *ior = outp->ior;
- struct nvkm_head *head;
- bool retrain = true;
- u32 datakbps = 0;
- u32 dataKBps;
- u32 linkKBps;
- u8 stat[3];
- int ret, i;
-
- mutex_lock(&outp->dp.mutex);
-
- /* Check that link configuration meets current requirements. */
- list_for_each_entry(head, &outp->disp->heads, head) {
- if (ior->asy.head & (1 << head->id)) {
- u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000;
- datakbps += khz * head->asy.or.depth;
- }
- }
-
- linkKBps = ior->dp.bw * 27000 * ior->dp.nr;
- dataKBps = DIV_ROUND_UP(datakbps, 8);
- OUTP_DBG(outp, "data %d KB/s link %d KB/s mst %d->%d",
- dataKBps, linkKBps, ior->dp.mst, outp->dp.lt.mst);
- if (linkKBps < dataKBps || ior->dp.mst != outp->dp.lt.mst) {
- OUTP_DBG(outp, "link requirements changed");
- goto done;
- }
-
- /* Check that link is still trained. */
- ret = nvkm_rdaux(outp->dp.aux, DPCD_LS02, stat, 3);
- if (ret) {
- OUTP_DBG(outp, "failed to read link status, assuming no sink");
- goto done;
- }
-
- if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
- for (i = 0; i < ior->dp.nr; i++) {
- u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
- if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
- !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
- !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
- OUTP_DBG(outp, "lane %d not equalised", lane);
- goto done;
- }
- }
- retrain = false;
- } else {
- OUTP_DBG(outp, "no inter-lane alignment");
- }
-
-done:
- if (retrain || !atomic_read(&outp->dp.lt.done))
- ret = nvkm_dp_train(outp, dataKBps);
- mutex_unlock(&outp->dp.mutex);
- return ret;
-}
-
-static bool
-nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp)
-{
- u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE];
- int i, j, k;
-
- if (outp->conn->info.type != DCB_CONNECTOR_eDP ||
- outp->dp.dpcd[DPCD_RC00_DPCD_REV] < 0x13 ||
- nvkm_rdaux(outp->dp.aux, DPCD_RC10_SUPPORTED_LINK_RATES(0),
- sink_rates, sizeof(sink_rates)))
- return false;
-
- for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) {
- const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10;
-
- if (!rate || WARN_ON(outp->dp.rates == ARRAY_SIZE(outp->dp.rate)))
- break;
-
- if (rate > outp->info.dpconf.link_bw * 27000) {
- OUTP_DBG(outp, "rate %d !outp", rate);
- continue;
- }
-
- for (j = 0; j < outp->dp.rates; j++) {
- if (rate > outp->dp.rate[j].rate) {
- for (k = outp->dp.rates; k > j; k--)
- outp->dp.rate[k] = outp->dp.rate[k - 1];
- break;
- }
- }
-
- outp->dp.rate[j].dpcd = i / 2;
- outp->dp.rate[j].rate = rate;
- outp->dp.rates++;
- }
-
- for (i = 0; i < outp->dp.rates; i++)
- OUTP_DBG(outp, "link_rate[%d] = %d", outp->dp.rate[i].dpcd, outp->dp.rate[i].rate);
+ nvkm_dp_disable(outp, outp->ior);
- return outp->dp.rates != 0;
-}
-
-/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps()
- * converted to work inside nvkm. This is a temporary holdover until we start
- * passing the drm_dp_aux device through NVKM
- */
-static int
-nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp)
-{
- struct nvkm_i2c_aux *aux = outp->dp.aux;
- u8 dpcd_ext[DP_RECEIVER_CAP_SIZE];
- int ret;
-
- ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE);
- if (ret < 0)
- return ret;
-
- /*
- * Prior to DP1.3 the bit represented by
- * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
- * If it is set DP_DPCD_REV at 0000h could be at a value less than
- * the true capability of the panel. The only way to check is to
- * then compare 0000h and 2200h.
- */
- if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
- DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
- return 0;
-
- ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext));
- if (ret < 0)
- return ret;
-
- if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
- OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n",
- outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]);
- return 0;
- }
-
- if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)))
- return 0;
-
- memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext));
-
- return 0;
+ nvkm_outp_release(outp);
}
void
@@ -711,66 +576,11 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr)
OUTP_DBG(outp, "aux power -> always");
nvkm_i2c_aux_monitor(aux, true);
outp->dp.aux_pwr = true;
-
- /* Detect any LTTPRs before reading DPCD receiver caps. */
- if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, outp->dp.lttpr, sizeof(outp->dp.lttpr)) &&
- outp->dp.lttpr[0] >= 0x14 && outp->dp.lttpr[2]) {
- switch (outp->dp.lttpr[2]) {
- case 0x80: outp->dp.lttprs = 1; break;
- case 0x40: outp->dp.lttprs = 2; break;
- case 0x20: outp->dp.lttprs = 3; break;
- case 0x10: outp->dp.lttprs = 4; break;
- case 0x08: outp->dp.lttprs = 5; break;
- case 0x04: outp->dp.lttprs = 6; break;
- case 0x02: outp->dp.lttprs = 7; break;
- case 0x01: outp->dp.lttprs = 8; break;
- default:
- /* Unknown LTTPR count, we'll switch to transparent mode. */
- WARN_ON(1);
- outp->dp.lttprs = 0;
- break;
- }
- } else {
- /* No LTTPR support, or zero LTTPR count - don't touch it at all. */
- memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr));
- }
-
- if (!nvkm_dp_read_dpcd_caps(outp)) {
- const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 };
- const u8 *rate;
- int rate_max;
-
- outp->dp.rates = 0;
- outp->dp.links = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
- outp->dp.links = min(outp->dp.links, outp->info.dpconf.link_nr);
- if (outp->dp.lttprs && outp->dp.lttpr[4])
- outp->dp.links = min_t(int, outp->dp.links, outp->dp.lttpr[4]);
-
- rate_max = outp->dp.dpcd[DPCD_RC01_MAX_LINK_RATE];
- rate_max = min(rate_max, outp->info.dpconf.link_bw);
- if (outp->dp.lttprs && outp->dp.lttpr[1])
- rate_max = min_t(int, rate_max, outp->dp.lttpr[1]);
-
- if (!nvkm_dp_enable_supported_link_rates(outp)) {
- for (rate = rates; *rate; rate++) {
- if (*rate > rate_max)
- continue;
-
- if (WARN_ON(outp->dp.rates == ARRAY_SIZE(outp->dp.rate)))
- break;
-
- outp->dp.rate[outp->dp.rates].dpcd = -1;
- outp->dp.rate[outp->dp.rates].rate = *rate * 27000;
- outp->dp.rates++;
- }
- }
- }
} else
if (!auxpwr && outp->dp.aux_pwr) {
OUTP_DBG(outp, "aux power -> demand");
nvkm_i2c_aux_monitor(aux, false);
outp->dp.aux_pwr = false;
- atomic_set(&outp->dp.lt.done, 0);
/* Restore eDP panel GPIO to its prior state if we changed it, as
* it could potentially interfere with other outputs.
@@ -793,6 +603,7 @@ nvkm_dp_fini(struct nvkm_outp *outp)
static void
nvkm_dp_init(struct nvkm_outp *outp)
{
+ nvkm_outp_init(outp);
nvkm_dp_enable(outp, outp->dp.enabled);
}
@@ -807,9 +618,18 @@ nvkm_dp_func = {
.dtor = nvkm_dp_dtor,
.init = nvkm_dp_init,
.fini = nvkm_dp_fini,
- .acquire = nvkm_dp_acquire,
+ .detect = nvkm_outp_detect,
+ .inherit = nvkm_outp_inherit,
+ .acquire = nvkm_outp_acquire,
.release = nvkm_dp_release,
- .disable = nvkm_dp_disable,
+ .bl.get = nvkm_outp_bl_get,
+ .bl.set = nvkm_outp_bl_set,
+ .dp.aux_pwr = nvkm_dp_aux_pwr,
+ .dp.aux_xfer = nvkm_dp_aux_xfer,
+ .dp.train = nvkm_dp_train,
+ .dp.drive = nvkm_dp_drive,
+ .dp.mst_id_get = nvkm_dp_mst_id_get,
+ .dp.mst_id_put = nvkm_dp_mst_id_put,
};
int
@@ -819,7 +639,7 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct n
struct nvkm_bios *bios = device->bios;
struct nvkm_i2c *i2c = device->i2c;
struct nvkm_outp *outp;
- u8 hdr, cnt, len;
+ u8 ver, hdr, cnt, len;
u32 data;
int ret;
@@ -847,7 +667,9 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct n
OUTP_DBG(outp, "bios dp %02x %02x %02x %02x", outp->dp.version, hdr, cnt, len);
+ data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len);
+ outp->dp.mst = data && ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 0x04);
+
mutex_init(&outp->dp.mutex);
- atomic_set(&outp->dp.lt.done, 0);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
index 23ae451ba4..1be97a68a8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -124,6 +124,7 @@ g84_sor = {
.state = nv50_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
+ .bl = &nv50_sor_bl,
.hdmi = &g84_sor_hdmi,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
index 67ef889a0c..843a2661ce 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
@@ -295,6 +295,7 @@ g94_sor = {
.clock = nv50_sor_clock,
.war_2 = g94_sor_war_2,
.war_3 = g94_sor_war_3,
+ .bl = &nv50_sor_bl,
.hdmi = &g84_sor_hdmi,
.dp = &g94_sor_dp,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
index 52099b75f5..ab0a85c924 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
@@ -24,6 +24,7 @@
#include "head.h"
#include "ior.h"
+#include <subdev/gsp.h>
#include <subdev/timer.h>
#include <nvif/class.h>
@@ -105,6 +106,7 @@ ga102_sor = {
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = ga102_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gv100_sor_hdmi,
.dp = &ga102_sor_dp,
.hda = &gv100_sor_hda,
@@ -146,5 +148,8 @@ int
ga102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_disp_new(&ga102_disp, device, type, inst, pdisp);
+
return nvkm_disp_new_(&ga102_disp, device, type, inst, pdisp);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index a48e9bdf4c..83a1323600 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -328,6 +328,7 @@ gf119_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gf119_sor_hdmi,
.dp = &gf119_sor_dp,
.hda = &gf119_sor_hda,
@@ -1038,7 +1039,6 @@ gf119_disp_super(struct work_struct *work)
continue;
nv50_disp_super_2_0(disp, head);
}
- nvkm_outp_route(disp);
list_for_each_entry(head, &disp->heads, head) {
if (!(mask[head->id] & 0x00010000))
continue;
@@ -1154,7 +1154,7 @@ gf119_disp_intr(struct nvkm_disp *disp)
}
void
-gf119_disp_fini(struct nvkm_disp *disp)
+gf119_disp_fini(struct nvkm_disp *disp, bool suspend)
{
struct nvkm_device *device = disp->engine.subdev.device;
/* disable all interrupts */
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
index 876a21a0ce..a3e2fbadad 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -115,6 +115,7 @@ gk104_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gk104_sor_hdmi,
.dp = &gf119_sor_dp,
.hda = &gf119_sor_hda,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
index b4d8e86861..688e123ad4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -70,6 +70,7 @@ gm107_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gk104_sor_hdmi,
.dp = &gm107_sor_dp,
.hda = &gf119_sor_hda,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
index 562ebae57d..511e7831b2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
@@ -68,15 +68,23 @@ gm200_sor_dp = {
};
void
-gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc)
+gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u32 khz, bool support, bool scrambling,
+ bool scrambling_low_rates)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(ior);
- const u32 ctrl = scdc & 0x3;
+ u32 ctrl = 0;
- nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
+ ior->tmds.high_speed = khz > 340000;
+
+ if (support && scrambling) {
+ if (ior->tmds.high_speed)
+ ctrl |= 0x00000002;
+ if (ior->tmds.high_speed || scrambling_low_rates)
+ ctrl |= 0x00000001;
+ }
- ior->tmds.high_speed = !!(scdc & 0x2);
+ nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
}
const struct nvkm_ior_func_hdmi
@@ -139,6 +147,7 @@ gm200_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gm200_sor_hdmi,
.dp = &gm200_sor_dp,
.hda = &gf119_sor_hda,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
index 7f1eb43320..4070447bd8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
@@ -37,6 +37,7 @@ gp100_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gm200_sor_hdmi,
.dp = &gm200_sor_dp,
.hda = &gf119_sor_hda,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
index 506ffbe7b8..6318721b66 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -182,11 +182,49 @@ gt215_sor_hdmi = {
.infoframe_vsi = gt215_sor_hdmi_infoframe_vsi,
};
+static int
+gt215_sor_bl_set(struct nvkm_ior *ior, int lvl)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ const u32 soff = nv50_ior_base(ior);
+ u32 div, val;
+
+ div = nvkm_rd32(device, 0x61c080 + soff);
+ val = (lvl * div) / 100;
+ if (div)
+ nvkm_wr32(device, 0x61c084 + soff, 0xc0000000 | val);
+
+ return 0;
+}
+
+static int
+gt215_sor_bl_get(struct nvkm_ior *ior)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ const u32 soff = nv50_ior_base(ior);
+ u32 div, val;
+
+ div = nvkm_rd32(device, 0x61c080 + soff);
+ val = nvkm_rd32(device, 0x61c084 + soff);
+ val &= 0x00ffffff;
+ if (div && div >= val)
+ return ((val * 100) + (div / 2)) / div;
+
+ return 100;
+}
+
+const struct nvkm_ior_func_bl
+gt215_sor_bl = {
+ .get = gt215_sor_bl_get,
+ .set = gt215_sor_bl_set,
+};
+
static const struct nvkm_ior_func
gt215_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gt215_sor_hdmi,
.dp = &gt215_sor_dp,
.hda = &gt215_sor_hda,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
index 4ebc030e40..cfa3698d3a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
@@ -96,7 +96,7 @@ gv100_sor_dp = {
.watermark = gv100_sor_dp_watermark,
};
-static void
+void
gv100_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
@@ -120,7 +120,7 @@ gv100_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 siz
nvkm_mask(device, 0x6f0100 + hoff, 0x00000001, 0x00000001);
}
-static void
+void
gv100_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
@@ -212,6 +212,7 @@ gv100_sor = {
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gv100_sor_hdmi,
.dp = &gv100_sor_dp,
.hda = &gv100_sor_hda,
@@ -863,7 +864,6 @@ gv100_disp_super(struct work_struct *work)
continue;
nv50_disp_super_2_0(disp, head);
}
- nvkm_outp_route(disp);
list_for_each_entry(head, &disp->heads, head) {
if (!(mask[head->id] & 0x00010000))
continue;
@@ -1115,7 +1115,7 @@ gv100_disp_intr(struct nvkm_disp *disp)
}
void
-gv100_disp_fini(struct nvkm_disp *disp)
+gv100_disp_fini(struct nvkm_disp *disp, bool suspend)
{
struct nvkm_device *device = disp->engine.subdev.device;
nvkm_wr32(device, 0x611db0, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
index da1b1a626e..3ba04bead2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -63,11 +63,18 @@ struct nvkm_ior_func {
void (*war_2)(struct nvkm_ior *);
void (*war_3)(struct nvkm_ior *);
+ const struct nvkm_ior_func_bl {
+ int (*get)(struct nvkm_ior *);
+ int (*set)(struct nvkm_ior *, int lvl);
+ } *bl;
+
const struct nvkm_ior_func_hdmi {
void (*ctrl)(struct nvkm_ior *, int head, bool enable, u8 max_ac_packet, u8 rekey);
- void (*scdc)(struct nvkm_ior *, u8 scdc);
+ void (*scdc)(struct nvkm_ior *, u32 khz, bool support, bool scrambling,
+ bool scrambling_low_rates);
void (*infoframe_avi)(struct nvkm_ior *, int head, void *data, u32 size);
void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size);
+ void (*audio)(struct nvkm_ior *, int head, bool enable);
} *hdmi;
const struct nvkm_ior_func_dp {
@@ -77,6 +84,8 @@ struct nvkm_ior_func {
void (*pattern)(struct nvkm_ior *, int pattern);
void (*drive)(struct nvkm_ior *, int ln, int pc,
int dc, int pe, int tx_pu);
+ int (*sst)(struct nvkm_ior *, int head, bool ef,
+ u32 watermark, u32 hblanksym, u32 vblanksym);
void (*vcpi)(struct nvkm_ior *, int head, u8 slot,
u8 slot_nr, u16 pbn, u16 aligned);
void (*audio)(struct nvkm_ior *, int head, bool enable);
@@ -122,6 +131,7 @@ int nv50_sor_cnt(struct nvkm_disp *, unsigned long *);
void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
void nv50_sor_clock(struct nvkm_ior *);
+extern const struct nvkm_ior_func_bl nv50_sor_bl;
int g84_sor_new(struct nvkm_disp *, int);
extern const struct nvkm_ior_func_hdmi g84_sor_hdmi;
@@ -138,6 +148,7 @@ void g94_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
void g94_sor_dp_activesym(struct nvkm_ior *, int, u8, u8, u8, u8);
void g94_sor_dp_watermark(struct nvkm_ior *, int, u8);
+extern const struct nvkm_ior_func_bl gt215_sor_bl;
extern const struct nvkm_ior_func_hdmi gt215_sor_hdmi;
void gt215_sor_dp_audio(struct nvkm_ior *, int, bool);
extern const struct nvkm_ior_func_hda gt215_sor_hda;
@@ -167,7 +178,7 @@ void gm107_sor_dp_pattern(struct nvkm_ior *, int);
void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *);
int gm200_sor_route_get(struct nvkm_outp *, int *);
extern const struct nvkm_ior_func_hdmi gm200_sor_hdmi;
-void gm200_sor_hdmi_scdc(struct nvkm_ior *, u8);
+void gm200_sor_hdmi_scdc(struct nvkm_ior *, u32, bool, bool, bool);
extern const struct nvkm_ior_func_dp gm200_sor_dp;
void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int);
@@ -176,6 +187,8 @@ int gp100_sor_new(struct nvkm_disp *, int);
int gv100_sor_cnt(struct nvkm_disp *, unsigned long *);
void gv100_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
extern const struct nvkm_ior_func_hdmi gv100_sor_hdmi;
+void gv100_sor_hdmi_infoframe_avi(struct nvkm_ior *, int, void *, u32);
+void gv100_sor_hdmi_infoframe_vsi(struct nvkm_ior *, int, void *, u32);
void gv100_sor_dp_audio(struct nvkm_ior *, int, bool);
void gv100_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
void gv100_sor_dp_watermark(struct nvkm_ior *, int, u8);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
index f96ba47526..e0c5fb6df3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
@@ -44,6 +44,7 @@ mcp89_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gt215_sor_hdmi,
.dp = &mcp89_sor_dp,
.hda = &gt215_sor_hda,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index be81168029..03a5f88a4b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -23,7 +23,9 @@
*/
#include "priv.h"
#include "chan.h"
+#include "conn.h"
#include "head.h"
+#include "dp.h"
#include "ior.h"
#include "outp.h"
@@ -156,6 +158,37 @@ nv50_pior_cnt(struct nvkm_disp *disp, unsigned long *pmask)
return 3;
}
+static int
+nv50_sor_bl_set(struct nvkm_ior *ior, int lvl)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ const u32 soff = nv50_ior_base(ior);
+ u32 div = 1025;
+ u32 val = (lvl * div) / 100;
+
+ nvkm_wr32(device, 0x61c084 + soff, 0x80000000 | val);
+ return 0;
+}
+
+static int
+nv50_sor_bl_get(struct nvkm_ior *ior)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ const u32 soff = nv50_ior_base(ior);
+ u32 div = 1025;
+ u32 val;
+
+ val = nvkm_rd32(device, 0x61c084 + soff);
+ val &= 0x000007ff;
+ return ((val * 100) + (div / 2)) / div;
+}
+
+const struct nvkm_ior_func_bl
+nv50_sor_bl = {
+ .get = nv50_sor_bl_get,
+ .set = nv50_sor_bl_set,
+};
+
void
nv50_sor_clock(struct nvkm_ior *sor)
{
@@ -220,6 +253,7 @@ nv50_sor = {
.state = nv50_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
+ .bl = &nv50_sor_bl,
};
static int
@@ -1254,10 +1288,6 @@ nv50_disp_super_2_2(struct nvkm_disp *disp, struct nvkm_head *head)
ior->asy.link = outp->lvds.dual ? 3 : 1;
}
- /* Handle any link training, etc. */
- if (outp && outp->func->acquire)
- outp->func->acquire(outp);
-
/* Execute OnInt2 IED script. */
nv50_disp_super_ied_on(head, ior, 0, khz);
@@ -1287,7 +1317,6 @@ nv50_disp_super_2_1(struct nvkm_disp *disp, struct nvkm_head *head)
void
nv50_disp_super_2_0(struct nvkm_disp *disp, struct nvkm_head *head)
{
- struct nvkm_outp *outp;
struct nvkm_ior *ior;
/* Determine which OR, if any, we're detaching from the head. */
@@ -1298,14 +1327,6 @@ nv50_disp_super_2_0(struct nvkm_disp *disp, struct nvkm_head *head)
/* Execute OffInt2 IED script. */
nv50_disp_super_ied_off(head, ior, 2);
-
- /* If we're shutting down the OR's only active head, execute
- * the output path's disable function.
- */
- if (ior->arm.head == (1 << head->id)) {
- if ((outp = ior->arm.outp) && outp->func->disable)
- outp->func->disable(outp, ior);
- }
}
void
@@ -1371,7 +1392,6 @@ nv50_disp_super(struct work_struct *work)
continue;
nv50_disp_super_2_0(disp, head);
}
- nvkm_outp_route(disp);
list_for_each_entry(head, &disp->heads, head) {
if (!(super & (0x00000200 << head->id)))
continue;
@@ -1484,7 +1504,7 @@ nv50_disp_intr(struct nvkm_disp *disp)
}
void
-nv50_disp_fini(struct nvkm_disp *disp)
+nv50_disp_fini(struct nvkm_disp *disp, bool suspend)
{
struct nvkm_device *device = disp->engine.subdev.device;
/* disable all interrupts */
@@ -1563,7 +1583,15 @@ nv50_disp_oneinit(struct nvkm_disp *disp)
const struct nvkm_disp_func *func = disp->func;
struct nvkm_subdev *subdev = &disp->engine.subdev;
struct nvkm_device *device = subdev->device;
+ struct nvkm_bios *bios = device->bios;
+ struct nvkm_outp *outp, *outt, *pair;
+ struct nvkm_conn *conn;
+ struct nvkm_ior *ior;
int ret, i;
+ u8 ver, hdr;
+ u32 data;
+ struct dcb_output dcbE;
+ struct nvbios_connE connE;
if (func->wndw.cnt) {
disp->wndw.nr = func->wndw.cnt(disp, &disp->wndw.mask);
@@ -1610,8 +1638,130 @@ nv50_disp_oneinit(struct nvkm_disp *disp)
if (ret)
return ret;
- return nvkm_ramht_new(device, func->ramht_size ? func->ramht_size :
- 0x1000, 0, disp->inst, &disp->ramht);
+ ret = nvkm_ramht_new(device, func->ramht_size ? func->ramht_size : 0x1000, 0, disp->inst,
+ &disp->ramht);
+ if (ret)
+ return ret;
+
+ /* Create output path objects for each VBIOS display path. */
+ i = -1;
+ while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
+ if (WARN_ON((ver & 0xf0) != 0x40))
+ return -EINVAL;
+ if (dcbE.type == DCB_OUTPUT_UNUSED)
+ continue;
+ if (dcbE.type == DCB_OUTPUT_EOL)
+ break;
+ outp = NULL;
+
+ switch (dcbE.type) {
+ case DCB_OUTPUT_ANALOG:
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ ret = nvkm_outp_new(disp, i, &dcbE, &outp);
+ break;
+ case DCB_OUTPUT_DP:
+ ret = nvkm_dp_new(disp, i, &dcbE, &outp);
+ break;
+ case DCB_OUTPUT_TV:
+ case DCB_OUTPUT_WFD:
+ /* No support for WFD yet. */
+ ret = -ENODEV;
+ continue;
+ default:
+ nvkm_warn(subdev, "dcb %d type %d unknown\n",
+ i, dcbE.type);
+ continue;
+ }
+
+ if (ret) {
+ if (outp) {
+ if (ret != -ENODEV)
+ OUTP_ERR(outp, "ctor failed: %d", ret);
+ else
+ OUTP_DBG(outp, "not supported");
+ nvkm_outp_del(&outp);
+ continue;
+ }
+ nvkm_error(subdev, "failed to create outp %d\n", i);
+ continue;
+ }
+
+ list_add_tail(&outp->head, &disp->outps);
+ }
+
+ /* Create connector objects based on available output paths. */
+ list_for_each_entry_safe(outp, outt, &disp->outps, head) {
+ /* VBIOS data *should* give us the most useful information. */
+ data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
+ &connE);
+
+ /* No bios connector data... */
+ if (!data) {
+ /* Heuristic: anything with the same ccb index is
+ * considered to be on the same connector, any
+ * output path without an associated ccb entry will
+ * be put on its own connector.
+ */
+ int ccb_index = outp->info.i2c_index;
+ if (ccb_index != 0xf) {
+ list_for_each_entry(pair, &disp->outps, head) {
+ if (pair->info.i2c_index == ccb_index) {
+ outp->conn = pair->conn;
+ break;
+ }
+ }
+ }
+
+ /* Connector shared with another output path. */
+ if (outp->conn)
+ continue;
+
+ memset(&connE, 0x00, sizeof(connE));
+ connE.type = DCB_CONNECTOR_NONE;
+ i = -1;
+ } else {
+ i = outp->info.connector;
+ }
+
+ /* Check that we haven't already created this connector. */
+ list_for_each_entry(conn, &disp->conns, head) {
+ if (conn->index == outp->info.connector) {
+ outp->conn = conn;
+ break;
+ }
+ }
+
+ if (outp->conn)
+ continue;
+
+ /* Apparently we need to create a new one! */
+ ret = nvkm_conn_new(disp, i, &connE, &outp->conn);
+ if (ret) {
+ nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret);
+ nvkm_conn_del(&outp->conn);
+ list_del(&outp->head);
+ nvkm_outp_del(&outp);
+ continue;
+ }
+
+ list_add_tail(&outp->conn->head, &disp->conns);
+ }
+
+ /* Enforce identity-mapped SOR assignment for panels, which have
+ * certain bits (ie. backlight controls) wired to a specific SOR.
+ */
+ list_for_each_entry(outp, &disp->outps, head) {
+ if (outp->conn->info.type == DCB_CONNECTOR_LVDS ||
+ outp->conn->info.type == DCB_CONNECTOR_eDP) {
+ ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1);
+ if (!WARN_ON(!ior))
+ ior->identity = true;
+ outp->identity = true;
+ }
+ }
+
+ return 0;
}
static const struct nvkm_disp_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
index 6094805fbd..28adc5a30f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -22,14 +22,16 @@
* Authors: Ben Skeggs
*/
#include "outp.h"
+#include "conn.h"
#include "dp.h"
#include "ior.h"
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
+#include <subdev/gpio.h>
#include <subdev/i2c.h>
-void
+static void
nvkm_outp_route(struct nvkm_disp *disp)
{
struct nvkm_outp *outp;
@@ -46,8 +48,8 @@ nvkm_outp_route(struct nvkm_disp *disp)
list_for_each_entry(ior, &disp->iors, head) {
if ((outp = ior->asy.outp)) {
- OUTP_DBG(outp, "acquire %s", ior->name);
if (ior->asy.outp != ior->arm.outp) {
+ OUTP_DBG(outp, "acquire %s", ior->name);
if (ior->func->route.set)
ior->func->route.set(outp, ior);
ior->arm.outp = ior->asy.outp;
@@ -87,22 +89,20 @@ nvkm_outp_xlat(struct nvkm_outp *outp, enum nvkm_ior_type *type)
}
void
-nvkm_outp_release(struct nvkm_outp *outp, u8 user)
+nvkm_outp_release_or(struct nvkm_outp *outp, u8 user)
{
struct nvkm_ior *ior = outp->ior;
OUTP_TRACE(outp, "release %02x &= %02x %p", outp->acquired, ~user, ior);
if (ior) {
outp->acquired &= ~user;
if (!outp->acquired) {
- if (outp->func->release && outp->ior)
- outp->func->release(outp);
outp->ior->asy.outp = NULL;
outp->ior = NULL;
}
}
}
-static inline int
+int
nvkm_outp_acquire_ior(struct nvkm_outp *outp, u8 user, struct nvkm_ior *ior)
{
outp->ior = ior;
@@ -140,7 +140,7 @@ nvkm_outp_acquire_hda(struct nvkm_outp *outp, enum nvkm_ior_type type,
}
int
-nvkm_outp_acquire(struct nvkm_outp *outp, u8 user, bool hda)
+nvkm_outp_acquire_or(struct nvkm_outp *outp, u8 user, bool hda)
{
struct nvkm_ior *ior = outp->ior;
enum nvkm_ior_proto proto;
@@ -207,39 +207,110 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user, bool hda)
return nvkm_outp_acquire_hda(outp, type, user, false);
}
+int
+nvkm_outp_bl_set(struct nvkm_outp *outp, int level)
+{
+ int ret;
+
+ ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false);
+ if (ret)
+ return ret;
+
+ if (outp->ior->func->bl)
+ ret = outp->ior->func->bl->set(outp->ior, level);
+ else
+ ret = -EINVAL;
+
+ nvkm_outp_release_or(outp, NVKM_OUTP_PRIV);
+ return ret;
+}
+
+int
+nvkm_outp_bl_get(struct nvkm_outp *outp)
+{
+ int ret;
+
+ ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false);
+ if (ret)
+ return ret;
+
+ if (outp->ior->func->bl)
+ ret = outp->ior->func->bl->get(outp->ior);
+ else
+ ret = -EINVAL;
+
+ nvkm_outp_release_or(outp, NVKM_OUTP_PRIV);
+ return ret;
+}
+
+int
+nvkm_outp_detect(struct nvkm_outp *outp)
+{
+ struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
+ int ret = -EINVAL;
+
+ if (outp->conn->info.hpd != DCB_GPIO_UNUSED) {
+ ret = nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, outp->conn->info.hpd);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ return 1;
+
+ /*TODO: Look into returning NOT_PRESENT if !HPD on DVI/HDMI.
+ *
+ * It's uncertain whether this is accurate for all older chipsets,
+ * so we're returning UNKNOWN, and the DRM will probe DDC instead.
+ */
+ if (outp->info.type == DCB_OUTPUT_DP)
+ return 0;
+ }
+
+ return ret;
+}
+
void
-nvkm_outp_fini(struct nvkm_outp *outp)
+nvkm_outp_release(struct nvkm_outp *outp)
{
- if (outp->func->fini)
- outp->func->fini(outp);
+ nvkm_outp_release_or(outp, NVKM_OUTP_USER);
+ nvkm_outp_route(outp->disp);
}
-static void
-nvkm_outp_init_route(struct nvkm_outp *outp)
+int
+nvkm_outp_acquire(struct nvkm_outp *outp, bool hda)
+{
+ int ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hda);
+
+ if (ret)
+ return ret;
+
+ nvkm_outp_route(outp->disp);
+ return 0;
+}
+
+struct nvkm_ior *
+nvkm_outp_inherit(struct nvkm_outp *outp)
{
struct nvkm_disp *disp = outp->disp;
+ struct nvkm_ior *ior;
enum nvkm_ior_proto proto;
enum nvkm_ior_type type;
- struct nvkm_ior *ior;
int id, link;
/* Find any OR from the class that is able to support this device. */
proto = nvkm_outp_xlat(outp, &type);
if (proto == UNKNOWN)
- return;
+ return NULL;
ior = nvkm_ior_find(disp, type, -1);
- if (!ior) {
- WARN_ON(1);
- return;
- }
+ if (WARN_ON(!ior))
+ return NULL;
/* Determine the specific OR, if any, this device is attached to. */
if (ior->func->route.get) {
id = ior->func->route.get(outp, &link);
if (id < 0) {
OUTP_DBG(outp, "no route");
- return;
+ return NULL;
}
} else {
/* Prior to DCB 4.1, this is hardwired like so. */
@@ -248,10 +319,24 @@ nvkm_outp_init_route(struct nvkm_outp *outp)
}
ior = nvkm_ior_find(disp, type, id);
- if (!ior) {
- WARN_ON(1);
+ if (WARN_ON(!ior))
+ return NULL;
+
+ return ior;
+}
+
+void
+nvkm_outp_init(struct nvkm_outp *outp)
+{
+ enum nvkm_ior_proto proto;
+ enum nvkm_ior_type type;
+ struct nvkm_ior *ior;
+
+ /* Find any OR from the class that is able to support this device. */
+ proto = nvkm_outp_xlat(outp, &type);
+ ior = outp->func->inherit(outp);
+ if (!ior)
return;
- }
/* Determine if the OR is already configured for this device. */
ior->func->state(ior, &ior->arm);
@@ -274,14 +359,6 @@ nvkm_outp_init_route(struct nvkm_outp *outp)
}
void
-nvkm_outp_init(struct nvkm_outp *outp)
-{
- nvkm_outp_init_route(outp);
- if (outp->func->init)
- outp->func->init(outp);
-}
-
-void
nvkm_outp_del(struct nvkm_outp **poutp)
{
struct nvkm_outp *outp = *poutp;
@@ -309,7 +386,8 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, struct nvkm_disp *disp,
outp->disp = disp;
outp->index = index;
outp->info = *dcbE;
- outp->i2c = nvkm_i2c_bus_find(i2c, dcbE->i2c_index);
+ if (!disp->rm.client.gsp)
+ outp->i2c = nvkm_i2c_bus_find(i2c, dcbE->i2c_index);
OUTP_DBG(outp, "type %02x loc %d or %d link %d con %x "
"edid %x bus %d head %x",
@@ -328,6 +406,13 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, struct nvkm_disp *disp,
static const struct nvkm_outp_func
nvkm_outp = {
+ .init = nvkm_outp_init,
+ .detect = nvkm_outp_detect,
+ .inherit = nvkm_outp_inherit,
+ .acquire = nvkm_outp_acquire,
+ .release = nvkm_outp_release,
+ .bl.get = nvkm_outp_bl_get,
+ .bl.set = nvkm_outp_bl_set,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index 4e7f873f66..ebd2f499b4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -35,6 +35,8 @@ struct nvkm_outp {
struct {
struct nvbios_dpout info;
u8 version;
+ bool mst;
+ bool increased_wm;
struct nvkm_i2c_aux *aux;
@@ -50,14 +52,13 @@ struct nvkm_outp {
u32 rate;
} rate[8];
int rates;
- int links;
struct mutex mutex;
struct {
- atomic_t done;
u8 nr;
u8 bw;
bool mst;
+ bool post_adj;
} lt;
} dp;
};
@@ -74,17 +75,45 @@ int nvkm_outp_new(struct nvkm_disp *, int index, struct dcb_output *, struct nvk
void nvkm_outp_del(struct nvkm_outp **);
void nvkm_outp_init(struct nvkm_outp *);
void nvkm_outp_fini(struct nvkm_outp *);
-int nvkm_outp_acquire(struct nvkm_outp *, u8 user, bool hda);
-void nvkm_outp_release(struct nvkm_outp *, u8 user);
-void nvkm_outp_route(struct nvkm_disp *);
+
+int nvkm_outp_detect(struct nvkm_outp *);
+
+struct nvkm_ior *nvkm_outp_inherit(struct nvkm_outp *);
+int nvkm_outp_acquire(struct nvkm_outp *, bool hda);
+int nvkm_outp_acquire_or(struct nvkm_outp *, u8 user, bool hda);
+int nvkm_outp_acquire_ior(struct nvkm_outp *, u8 user, struct nvkm_ior *);
+void nvkm_outp_release(struct nvkm_outp *);
+void nvkm_outp_release_or(struct nvkm_outp *, u8 user);
+
+int nvkm_outp_bl_get(struct nvkm_outp *);
+int nvkm_outp_bl_set(struct nvkm_outp *, int level);
struct nvkm_outp_func {
void *(*dtor)(struct nvkm_outp *);
void (*init)(struct nvkm_outp *);
void (*fini)(struct nvkm_outp *);
- int (*acquire)(struct nvkm_outp *);
+
+ int (*detect)(struct nvkm_outp *);
+ int (*edid_get)(struct nvkm_outp *, u8 *data, u16 *size);
+
+ struct nvkm_ior *(*inherit)(struct nvkm_outp *);
+ int (*acquire)(struct nvkm_outp *, bool hda);
void (*release)(struct nvkm_outp *);
- void (*disable)(struct nvkm_outp *, struct nvkm_ior *);
+
+ struct {
+ int (*get)(struct nvkm_outp *);
+ int (*set)(struct nvkm_outp *, int level);
+ } bl;
+
+ struct {
+ int (*aux_pwr)(struct nvkm_outp *, bool pu);
+ int (*aux_xfer)(struct nvkm_outp *, u8 type, u32 addr, u8 *data, u8 *size);
+ int (*rates)(struct nvkm_outp *);
+ int (*train)(struct nvkm_outp *, bool retrain);
+ int (*drive)(struct nvkm_outp *, u8 lanes, u8 pe[4], u8 vs[4]);
+ int (*mst_id_get)(struct nvkm_outp *, u32 *id);
+ int (*mst_id_put)(struct nvkm_outp *, u32 id);
+ } dp;
};
#define OUTP_MSG(o,l,f,a...) do { \
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
index ec5292a8f3..a3fd7cb7c4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
@@ -8,6 +8,9 @@ struct nvkm_head;
struct nvkm_outp;
struct dcb_output;
+int r535_disp_new(const struct nvkm_disp_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
+ struct nvkm_disp **);
+
int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_disp *);
int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
@@ -15,9 +18,10 @@ int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, enum nvk
void nvkm_disp_vblank(struct nvkm_disp *, int head);
struct nvkm_disp_func {
+ void (*dtor)(struct nvkm_disp *);
int (*oneinit)(struct nvkm_disp *);
int (*init)(struct nvkm_disp *);
- void (*fini)(struct nvkm_disp *);
+ void (*fini)(struct nvkm_disp *, bool suspend);
void (*intr)(struct nvkm_disp *);
void (*intr_error)(struct nvkm_disp *, int chid);
@@ -32,7 +36,7 @@ struct nvkm_disp_func {
u16 ramht_size;
- const struct nvkm_sclass root;
+ struct nvkm_sclass root;
struct nvkm_disp_user {
struct nvkm_sclass base;
@@ -44,7 +48,7 @@ struct nvkm_disp_func {
int nv50_disp_oneinit(struct nvkm_disp *);
int nv50_disp_init(struct nvkm_disp *);
-void nv50_disp_fini(struct nvkm_disp *);
+void nv50_disp_fini(struct nvkm_disp *, bool suspend);
void nv50_disp_intr(struct nvkm_disp *);
extern const struct nvkm_enum nv50_disp_intr_error_type[];
void nv50_disp_super(struct work_struct *);
@@ -56,12 +60,12 @@ void nv50_disp_super_2_2(struct nvkm_disp *, struct nvkm_head *);
void nv50_disp_super_3_0(struct nvkm_disp *, struct nvkm_head *);
int gf119_disp_init(struct nvkm_disp *);
-void gf119_disp_fini(struct nvkm_disp *);
+void gf119_disp_fini(struct nvkm_disp *, bool suspend);
void gf119_disp_intr(struct nvkm_disp *);
void gf119_disp_super(struct work_struct *);
void gf119_disp_intr_error(struct nvkm_disp *, int);
-void gv100_disp_fini(struct nvkm_disp *);
+void gv100_disp_fini(struct nvkm_disp *, bool suspend);
void gv100_disp_intr(struct nvkm_disp *);
void gv100_disp_super(struct work_struct *);
int gv100_disp_wndw_cnt(struct nvkm_disp *, unsigned long *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/r535.c
new file mode 100644
index 0000000000..6a0a4d3b89
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/r535.c
@@ -0,0 +1,1714 @@
+/*
+ * Copyright 2023 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 "priv.h"
+#include "chan.h"
+#include "conn.h"
+#include "dp.h"
+#include "head.h"
+#include "ior.h"
+#include "outp.h"
+
+#include <core/ramht.h>
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+#include <subdev/gsp.h>
+#include <subdev/mmu.h>
+#include <subdev/vfn.h>
+
+#include <nvhw/drf.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/class/cl2080_notification.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073dfp.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073dp.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073specific.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073system.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080internal.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>
+#include <nvrm/535.113.01/nvidia/generated/g_allclasses.h>
+#include <nvrm/535.113.01/nvidia/generated/g_mem_desc_nvoc.h>
+#include <nvrm/535.113.01/nvidia/inc/kernel/os/nv_memory_type.h>
+
+#include <linux/acpi.h>
+
+static u64
+r535_chan_user(struct nvkm_disp_chan *chan, u64 *psize)
+{
+ switch (chan->object.oclass & 0xff) {
+ case 0x7d: *psize = 0x10000; return 0x680000;
+ case 0x7e: *psize = 0x01000; return 0x690000 + (chan->head * *psize);
+ case 0x7b: *psize = 0x01000; return 0x6b0000 + (chan->head * *psize);
+ case 0x7a: *psize = 0x01000; return 0x6d8000 + (chan->head * *psize);
+ default:
+ BUG_ON(1);
+ break;
+ }
+
+ return 0ULL;
+}
+
+static void
+r535_chan_intr(struct nvkm_disp_chan *chan, bool en)
+{
+}
+
+static void
+r535_chan_fini(struct nvkm_disp_chan *chan)
+{
+ nvkm_gsp_rm_free(&chan->rm.object);
+}
+
+static int
+r535_chan_push(struct nvkm_disp_chan *chan)
+{
+ struct nvkm_gsp *gsp = chan->disp->engine.subdev.device->gsp;
+ NV2080_CTRL_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ if (chan->memory) {
+ switch (nvkm_memory_target(chan->memory)) {
+ case NVKM_MEM_TARGET_NCOH:
+ ctrl->addressSpace = ADDR_SYSMEM;
+ ctrl->cacheSnoop = 0;
+ break;
+ case NVKM_MEM_TARGET_HOST:
+ ctrl->addressSpace = ADDR_SYSMEM;
+ ctrl->cacheSnoop = 1;
+ break;
+ case NVKM_MEM_TARGET_VRAM:
+ ctrl->addressSpace = ADDR_FBMEM;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ ctrl->physicalAddr = nvkm_memory_addr(chan->memory);
+ ctrl->limit = nvkm_memory_size(chan->memory) - 1;
+ }
+
+ ctrl->hclass = chan->object.oclass;
+ ctrl->channelInstance = chan->head;
+ ctrl->valid = ((chan->object.oclass & 0xff) != 0x7a) ? 1 : 0;
+
+ return nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
+}
+
+static int
+r535_curs_init(struct nvkm_disp_chan *chan)
+{
+ NV50VAIO_CHANNELPIO_ALLOCATION_PARAMETERS *args;
+ int ret;
+
+ ret = r535_chan_push(chan);
+ if (ret)
+ return ret;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->disp->rm.object,
+ (chan->object.oclass << 16) | chan->head,
+ chan->object.oclass, sizeof(*args), &chan->rm.object);
+ if (IS_ERR(args))
+ return PTR_ERR(args);
+
+ args->channelInstance = chan->head;
+
+ return nvkm_gsp_rm_alloc_wr(&chan->rm.object, args);
+}
+
+static const struct nvkm_disp_chan_func
+r535_curs_func = {
+ .init = r535_curs_init,
+ .fini = r535_chan_fini,
+ .intr = r535_chan_intr,
+ .user = r535_chan_user,
+};
+
+static const struct nvkm_disp_chan_user
+r535_curs = {
+ .func = &r535_curs_func,
+ .user = 73,
+};
+
+static int
+r535_dmac_bind(struct nvkm_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 |
+ (chan->disp->rm.client.object.handle & 0x3fff));
+}
+
+static void
+r535_dmac_fini(struct nvkm_disp_chan *chan)
+{
+ struct nvkm_device *device = chan->disp->engine.subdev.device;
+ const u32 uoff = (chan->chid.user - 1) * 0x1000;
+
+ chan->suspend_put = nvkm_rd32(device, 0x690000 + uoff);
+ r535_chan_fini(chan);
+}
+
+static int
+r535_dmac_init(struct nvkm_disp_chan *chan)
+{
+ NV50VAIO_CHANNELDMA_ALLOCATION_PARAMETERS *args;
+ int ret;
+
+ ret = r535_chan_push(chan);
+ if (ret)
+ return ret;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->disp->rm.object,
+ (chan->object.oclass << 16) | chan->head,
+ chan->object.oclass, sizeof(*args), &chan->rm.object);
+ if (IS_ERR(args))
+ return PTR_ERR(args);
+
+ args->channelInstance = chan->head;
+ args->offset = chan->suspend_put;
+
+ return nvkm_gsp_rm_alloc_wr(&chan->rm.object, args);
+}
+
+static int
+r535_dmac_push(struct nvkm_disp_chan *chan, u64 memory)
+{
+ chan->memory = nvkm_umem_search(chan->object.client, memory);
+ if (IS_ERR(chan->memory))
+ return PTR_ERR(chan->memory);
+
+ return 0;
+}
+
+static const struct nvkm_disp_chan_func
+r535_dmac_func = {
+ .push = r535_dmac_push,
+ .init = r535_dmac_init,
+ .fini = r535_dmac_fini,
+ .intr = r535_chan_intr,
+ .user = r535_chan_user,
+ .bind = r535_dmac_bind,
+};
+
+static const struct nvkm_disp_chan_func
+r535_wimm_func = {
+ .push = r535_dmac_push,
+ .init = r535_dmac_init,
+ .fini = r535_dmac_fini,
+ .intr = r535_chan_intr,
+ .user = r535_chan_user,
+};
+
+static const struct nvkm_disp_chan_user
+r535_wimm = {
+ .func = &r535_wimm_func,
+ .user = 33,
+};
+
+static const struct nvkm_disp_chan_user
+r535_wndw = {
+ .func = &r535_dmac_func,
+ .user = 1,
+};
+
+static void
+r535_core_fini(struct nvkm_disp_chan *chan)
+{
+ struct nvkm_device *device = chan->disp->engine.subdev.device;
+
+ chan->suspend_put = nvkm_rd32(device, 0x680000);
+ r535_chan_fini(chan);
+}
+
+static const struct nvkm_disp_chan_func
+r535_core_func = {
+ .push = r535_dmac_push,
+ .init = r535_dmac_init,
+ .fini = r535_core_fini,
+ .intr = r535_chan_intr,
+ .user = r535_chan_user,
+ .bind = r535_dmac_bind,
+};
+
+static const struct nvkm_disp_chan_user
+r535_core = {
+ .func = &r535_core_func,
+ .user = 0,
+};
+
+static int
+r535_sor_bl_set(struct nvkm_ior *sor, int lvl)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_SET_BACKLIGHT_BRIGHTNESS,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+ ctrl->brightness = lvl;
+
+ return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
+}
+
+static int
+r535_sor_bl_get(struct nvkm_ior *sor)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_PARAMS *ctrl;
+ int ret, lvl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_GET_BACKLIGHT_BRIGHTNESS,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ lvl = ctrl->brightness;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return lvl;
+}
+
+static const struct nvkm_ior_func_bl
+r535_sor_bl = {
+ .get = r535_sor_bl_get,
+ .set = r535_sor_bl_set,
+};
+
+static void
+r535_sor_hda_eld(struct nvkm_ior *sor, int head, u8 *data, u8 size)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_DFP_SET_ELD_AUDIO_CAP_PARAMS *ctrl;
+
+ if (WARN_ON(size > sizeof(ctrl->bufferELD)))
+ return;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DFP_SET_ELD_AUDIO_CAPS, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+ ctrl->numELDSize = size;
+ memcpy(ctrl->bufferELD, data, size);
+ ctrl->maxFreqSupported = 0; //XXX
+ ctrl->ctrl = NVDEF(NV0073, CTRL_DFP_ELD_AUDIO_CAPS_CTRL, PD, TRUE);
+ ctrl->ctrl |= NVDEF(NV0073, CTRL_DFP_ELD_AUDIO_CAPS_CTRL, ELDV, TRUE);
+ ctrl->deviceEntry = head;
+
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static void
+r535_sor_hda_hpd(struct nvkm_ior *sor, int head, bool present)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_DFP_SET_ELD_AUDIO_CAP_PARAMS *ctrl;
+
+ if (present)
+ return;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DFP_SET_ELD_AUDIO_CAPS, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+ ctrl->deviceEntry = head;
+
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static const struct nvkm_ior_func_hda
+r535_sor_hda = {
+ .hpd = r535_sor_hda_hpd,
+ .eld = r535_sor_hda_eld,
+};
+
+static void
+r535_sor_dp_audio_mute(struct nvkm_ior *sor, bool mute)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_DP_SET_AUDIO_MUTESTREAM_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_SET_AUDIO_MUTESTREAM, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+ ctrl->mute = mute;
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static void
+r535_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_DFP_SET_AUDIO_ENABLE_PARAMS *ctrl;
+
+ if (!enable)
+ r535_sor_dp_audio_mute(sor, true);
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DFP_SET_AUDIO_ENABLE, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+ ctrl->enable = enable;
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+
+ if (enable)
+ r535_sor_dp_audio_mute(sor, false);
+}
+
+static void
+r535_sor_dp_vcpi(struct nvkm_ior *sor, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned_pbn)
+{
+ struct nvkm_disp *disp = sor->disp;
+ struct NV0073_CTRL_CMD_DP_CONFIG_STREAM_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_CONFIG_STREAM, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->head = head;
+ ctrl->sorIndex = sor->id;
+ ctrl->dpLink = sor->asy.link == 2;
+ ctrl->bEnableOverride = 1;
+ ctrl->bMST = 1;
+ ctrl->hBlankSym = 0;
+ ctrl->vBlankSym = 0;
+ ctrl->colorFormat = 0;
+ ctrl->bEnableTwoHeadOneOr = 0;
+ ctrl->singleHeadMultistreamMode = 0;
+ ctrl->MST.slotStart = slot;
+ ctrl->MST.slotEnd = slot + slot_nr - 1;
+ ctrl->MST.PBN = pbn;
+ ctrl->MST.Timeslice = aligned_pbn;
+ ctrl->MST.sendACT = 0;
+ ctrl->MST.singleHeadMSTPipeline = 0;
+ ctrl->MST.bEnableAudioOverRightPanel = 0;
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static int
+r535_sor_dp_sst(struct nvkm_ior *sor, int head, bool ef,
+ u32 watermark, u32 hblanksym, u32 vblanksym)
+{
+ struct nvkm_disp *disp = sor->disp;
+ struct NV0073_CTRL_CMD_DP_CONFIG_STREAM_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_CONFIG_STREAM, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->head = head;
+ ctrl->sorIndex = sor->id;
+ ctrl->dpLink = sor->asy.link == 2;
+ ctrl->bEnableOverride = 1;
+ ctrl->bMST = 0;
+ ctrl->hBlankSym = hblanksym;
+ ctrl->vBlankSym = vblanksym;
+ ctrl->colorFormat = 0;
+ ctrl->bEnableTwoHeadOneOr = 0;
+ ctrl->SST.bEnhancedFraming = ef;
+ ctrl->SST.tuSize = 64;
+ ctrl->SST.waterMark = watermark;
+ ctrl->SST.bEnableAudioOverRightPanel = 0;
+ return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
+}
+
+static const struct nvkm_ior_func_dp
+r535_sor_dp = {
+ .sst = r535_sor_dp_sst,
+ .vcpi = r535_sor_dp_vcpi,
+ .audio = r535_sor_dp_audio,
+};
+
+static void
+r535_sor_hdmi_scdc(struct nvkm_ior *sor, u32 khz, bool support, bool scrambling,
+ bool scrambling_low_rates)
+{
+ struct nvkm_outp *outp = sor->asy.outp;
+ struct nvkm_disp *disp = outp->disp;
+ NV0073_CTRL_SPECIFIC_SET_HDMI_SINK_CAPS_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_SINK_CAPS, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(outp->index);
+ ctrl->caps = 0;
+ if (support)
+ ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, SCDC_SUPPORTED, TRUE);
+ if (scrambling)
+ ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, GT_340MHZ_CLOCK_SUPPORTED, TRUE);
+ if (scrambling_low_rates)
+ ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, LTE_340MHZ_SCRAMBLING_SUPPORTED, TRUE);
+
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static void
+r535_sor_hdmi_ctrl_audio_mute(struct nvkm_outp *outp, bool mute)
+{
+ struct nvkm_disp *disp = outp->disp;
+ NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_AUDIO_MUTESTREAM_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_AUDIO_MUTESTREAM, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(outp->index);
+ ctrl->mute = mute;
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static void
+r535_sor_hdmi_ctrl_audio(struct nvkm_outp *outp, bool enable)
+{
+ struct nvkm_disp *disp = outp->disp;
+ NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(outp->index);
+ ctrl->transmitControl =
+ NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, ENABLE, YES) |
+ NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, OTHER_FRAME, DISABLE) |
+ NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, SINGLE_FRAME, DISABLE) |
+ NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, ON_HBLANK, DISABLE) |
+ NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, VIDEO_FMT, SW_CONTROLLED) |
+ NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, RESERVED_LEGACY_MODE, NO);
+ ctrl->packetSize = 10;
+ ctrl->aPacket[0] = 0x03;
+ ctrl->aPacket[1] = 0x00;
+ ctrl->aPacket[2] = 0x00;
+ ctrl->aPacket[3] = enable ? 0x10 : 0x01;
+ ctrl->aPacket[4] = 0x00;
+ ctrl->aPacket[5] = 0x00;
+ ctrl->aPacket[6] = 0x00;
+ ctrl->aPacket[7] = 0x00;
+ ctrl->aPacket[8] = 0x00;
+ ctrl->aPacket[9] = 0x00;
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static void
+r535_sor_hdmi_audio(struct nvkm_ior *sor, int head, bool enable)
+{
+ struct nvkm_device *device = sor->disp->engine.subdev.device;
+ const u32 hdmi = head * 0x400;
+
+ r535_sor_hdmi_ctrl_audio(sor->asy.outp, enable);
+ r535_sor_hdmi_ctrl_audio_mute(sor->asy.outp, !enable);
+
+ /* General Control (GCP). */
+ nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000);
+ nvkm_wr32(device, 0x6f00cc + hdmi, !enable ? 0x00000001 : 0x00000010);
+ nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000001);
+}
+
+static void
+r535_sor_hdmi_ctrl(struct nvkm_ior *sor, int head, bool enable, u8 max_ac_packet, u8 rekey)
+{
+ struct nvkm_disp *disp = sor->disp;
+ NV0073_CTRL_SPECIFIC_SET_HDMI_ENABLE_PARAMS *ctrl;
+
+ if (!enable)
+ return;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_ENABLE, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return;
+
+ ctrl->displayId = BIT(sor->asy.outp->index);
+ ctrl->enable = enable;
+
+ WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
+}
+
+static const struct nvkm_ior_func_hdmi
+r535_sor_hdmi = {
+ .ctrl = r535_sor_hdmi_ctrl,
+ .scdc = r535_sor_hdmi_scdc,
+ /*TODO: SF_USER -> KMS. */
+ .infoframe_avi = gv100_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = gv100_sor_hdmi_infoframe_vsi,
+ .audio = r535_sor_hdmi_audio,
+};
+
+static const struct nvkm_ior_func
+r535_sor = {
+ .hdmi = &r535_sor_hdmi,
+ .dp = &r535_sor_dp,
+ .hda = &r535_sor_hda,
+ .bl = &r535_sor_bl,
+};
+
+static int
+r535_sor_new(struct nvkm_disp *disp, int id)
+{
+ return nvkm_ior_new_(&r535_sor, disp, SOR, id, true/*XXX: hda cap*/);
+}
+
+static int
+r535_sor_cnt(struct nvkm_disp *disp, unsigned long *pmask)
+{
+ *pmask = 0xf;
+ return 4;
+}
+
+static void
+r535_head_vblank_put(struct nvkm_head *head)
+{
+ struct nvkm_device *device = head->disp->engine.subdev.device;
+
+ nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000002, 0x00000000);
+}
+
+static void
+r535_head_vblank_get(struct nvkm_head *head)
+{
+ struct nvkm_device *device = head->disp->engine.subdev.device;
+
+ nvkm_wr32(device, 0x611800 + (head->id * 4), 0x00000002);
+ nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000002, 0x00000002);
+}
+
+static void
+r535_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
+{
+}
+
+static const struct nvkm_head_func
+r535_head = {
+ .state = r535_head_state,
+ .vblank_get = r535_head_vblank_get,
+ .vblank_put = r535_head_vblank_put,
+};
+
+static struct nvkm_conn *
+r535_conn_new(struct nvkm_disp *disp, u32 id)
+{
+ NV0073_CTRL_SPECIFIC_GET_CONNECTOR_DATA_PARAMS *ctrl;
+ struct nvbios_connE dcbE = {};
+ struct nvkm_conn *conn;
+ int ret, index;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_GET_CONNECTOR_DATA, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return (void *)ctrl;
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(id);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ERR_PTR(ret);
+ }
+
+ list_for_each_entry(conn, &disp->conns, head) {
+ if (conn->index == ctrl->data[0].index) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return conn;
+ }
+ }
+
+ dcbE.type = ctrl->data[0].type;
+ index = ctrl->data[0].index;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ ret = nvkm_conn_new(disp, index, &dcbE, &conn);
+ if (ret)
+ return ERR_PTR(ret);
+
+ list_add_tail(&conn->head, &disp->conns);
+ return conn;
+}
+
+static void
+r535_outp_release(struct nvkm_outp *outp)
+{
+ outp->disp->rm.assigned_sors &= ~BIT(outp->ior->id);
+ outp->ior->asy.outp = NULL;
+ outp->ior = NULL;
+}
+
+static int
+r535_outp_acquire(struct nvkm_outp *outp, bool hda)
+{
+ struct nvkm_disp *disp = outp->disp;
+ struct nvkm_ior *ior;
+ NV0073_CTRL_DFP_ASSIGN_SOR_PARAMS *ctrl;
+ int ret, or;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DFP_ASSIGN_SOR, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(outp->index);
+ ctrl->sorExcludeMask = disp->rm.assigned_sors;
+ if (hda)
+ ctrl->flags |= NVDEF(NV0073_CTRL, DFP_ASSIGN_SOR_FLAGS, AUDIO, OPTIMAL);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ for (or = 0; or < ARRAY_SIZE(ctrl->sorAssignListWithTag); or++) {
+ if (ctrl->sorAssignListWithTag[or].displayMask & BIT(outp->index)) {
+ disp->rm.assigned_sors |= BIT(or);
+ break;
+ }
+ }
+
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ if (WARN_ON(or == ARRAY_SIZE(ctrl->sorAssignListWithTag)))
+ return -EINVAL;
+
+ ior = nvkm_ior_find(disp, SOR, or);
+ if (WARN_ON(!ior))
+ return -EINVAL;
+
+ nvkm_outp_acquire_ior(outp, NVKM_OUTP_USER, ior);
+ return 0;
+}
+
+static int
+r535_disp_head_displayid(struct nvkm_disp *disp, int head, u32 *displayid)
+{
+ NV0073_CTRL_SYSTEM_GET_ACTIVE_PARAMS *ctrl;
+ int ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SYSTEM_GET_ACTIVE, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->head = head;
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ *displayid = ctrl->displayId;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return 0;
+}
+
+static struct nvkm_ior *
+r535_outp_inherit(struct nvkm_outp *outp)
+{
+ struct nvkm_disp *disp = outp->disp;
+ struct nvkm_head *head;
+ u32 displayid;
+ int ret;
+
+ list_for_each_entry(head, &disp->heads, head) {
+ ret = r535_disp_head_displayid(disp, head->id, &displayid);
+ if (WARN_ON(ret))
+ return NULL;
+
+ if (displayid == BIT(outp->index)) {
+ NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS *ctrl;
+ u32 id, proto;
+ struct nvkm_ior *ior;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return NULL;
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = displayid;
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return NULL;
+ }
+
+ id = ctrl->index;
+ proto = ctrl->protocol;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ ior = nvkm_ior_find(disp, SOR, id);
+ if (WARN_ON(!ior))
+ return NULL;
+
+ switch (proto) {
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A:
+ ior->arm.proto = TMDS;
+ ior->arm.link = 1;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B:
+ ior->arm.proto = TMDS;
+ ior->arm.link = 2;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS:
+ ior->arm.proto = TMDS;
+ ior->arm.link = 3;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A:
+ ior->arm.proto = DP;
+ ior->arm.link = 1;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B:
+ ior->arm.proto = DP;
+ ior->arm.link = 2;
+ break;
+ default:
+ WARN_ON(1);
+ return NULL;
+ }
+
+ ior->arm.proto_evo = proto;
+ ior->arm.head = BIT(head->id);
+ disp->rm.assigned_sors |= BIT(ior->id);
+ return ior;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+r535_outp_dfp_get_info(struct nvkm_outp *outp)
+{
+ NV0073_CTRL_DFP_GET_INFO_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+ int ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DFP_GET_INFO, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->displayId = BIT(outp->index);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ nvkm_debug(&disp->engine.subdev, "DFP %08x: flags:%08x flags2:%08x\n",
+ ctrl->displayId, ctrl->flags, ctrl->flags2);
+
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return 0;
+}
+
+static int
+r535_outp_detect(struct nvkm_outp *outp)
+{
+ NV0073_CTRL_SYSTEM_GET_CONNECT_STATE_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+ int ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SYSTEM_GET_CONNECT_STATE, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayMask = BIT(outp->index);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ if (ctrl->displayMask & BIT(outp->index)) {
+ ret = r535_outp_dfp_get_info(outp);
+ if (ret == 0)
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+}
+
+static int
+r535_dp_mst_id_put(struct nvkm_outp *outp, u32 id)
+{
+ NV0073_CTRL_CMD_DP_TOPOLOGY_FREE_DISPLAYID_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_TOPOLOGY_FREE_DISPLAYID, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = id;
+ return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
+}
+
+static int
+r535_dp_mst_id_get(struct nvkm_outp *outp, u32 *pid)
+{
+ NV0073_CTRL_CMD_DP_TOPOLOGY_ALLOCATE_DISPLAYID_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+ int ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_TOPOLOGY_ALLOCATE_DISPLAYID,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(outp->index);
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ *pid = ctrl->displayIdAssigned;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return 0;
+}
+
+static int
+r535_dp_drive(struct nvkm_outp *outp, u8 lanes, u8 pe[4], u8 vs[4])
+{
+ NV0073_CTRL_DP_LANE_DATA_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_SET_LANE_DATA, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->displayId = BIT(outp->index);
+ ctrl->numLanes = lanes;
+ for (int i = 0; i < lanes; i++)
+ ctrl->data[i] = NVVAL(NV0073_CTRL, DP_LANE_DATA, PREEMPHASIS, pe[i]) |
+ NVVAL(NV0073_CTRL, DP_LANE_DATA, DRIVECURRENT, vs[i]);
+
+ return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
+}
+
+static int
+r535_dp_train_target(struct nvkm_outp *outp, u8 target, bool mst, u8 link_nr, u8 link_bw)
+{
+ struct nvkm_disp *disp = outp->disp;
+ NV0073_CTRL_DP_CTRL_PARAMS *ctrl;
+ int ret, retries;
+ u32 cmd, data;
+
+ cmd = NVDEF(NV0073_CTRL, DP_CMD, SET_LANE_COUNT, TRUE) |
+ NVDEF(NV0073_CTRL, DP_CMD, SET_LINK_BW, TRUE) |
+ NVDEF(NV0073_CTRL, DP_CMD, TRAIN_PHY_REPEATER, YES);
+ data = NVVAL(NV0073_CTRL, DP_DATA, SET_LANE_COUNT, link_nr) |
+ NVVAL(NV0073_CTRL, DP_DATA, SET_LINK_BW, link_bw) |
+ NVVAL(NV0073_CTRL, DP_DATA, TARGET, target);
+
+ if (mst)
+ cmd |= NVDEF(NV0073_CTRL, DP_CMD, SET_FORMAT_MODE, MULTI_STREAM);
+
+ if (outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
+ cmd |= NVDEF(NV0073_CTRL, DP_CMD, SET_ENHANCED_FRAMING, TRUE);
+
+ if (target == 0 &&
+ (outp->dp.dpcd[DPCD_RC02] & 0x20) &&
+ !(outp->dp.dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED))
+ cmd |= NVDEF(NV0073_CTRL, DP_CMD, POST_LT_ADJ_REQ_GRANTED, YES);
+
+ /* We should retry up to 3 times, but only if GSP asks politely */
+ for (retries = 0; retries < 3; ++retries) {
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DP_CTRL,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(outp->index);
+ ctrl->retryTimeMs = 0;
+ ctrl->cmd = cmd;
+ ctrl->data = data;
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret == -EAGAIN && ctrl->retryTimeMs) {
+ /*
+ * Device (likely an eDP panel) isn't ready yet, wait for the time specified
+ * by GSP before retrying again
+ */
+ nvkm_debug(&disp->engine.subdev,
+ "Waiting %dms for GSP LT panel delay before retrying\n",
+ ctrl->retryTimeMs);
+ msleep(ctrl->retryTimeMs);
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ } else {
+ /* GSP didn't say to retry, or we were successful */
+ if (ctrl->err)
+ ret = -EIO;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+r535_dp_train(struct nvkm_outp *outp, bool retrain)
+{
+ for (int target = outp->dp.lttprs; target >= 0; target--) {
+ int ret = r535_dp_train_target(outp, target, outp->dp.lt.mst,
+ outp->dp.lt.nr,
+ outp->dp.lt.bw);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+r535_dp_rates(struct nvkm_outp *outp)
+{
+ NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+
+ if (outp->conn->info.type != DCB_CONNECTOR_eDP ||
+ !outp->dp.rates || outp->dp.rate[0].dpcd < 0)
+ return 0;
+
+ if (WARN_ON(outp->dp.rates > ARRAY_SIZE(ctrl->linkRateTbl)))
+ return -EINVAL;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->displayId = BIT(outp->index);
+ for (int i = 0; i < outp->dp.rates; i++)
+ ctrl->linkRateTbl[outp->dp.rate[i].dpcd] = outp->dp.rate[i].rate * 10 / 200;
+
+ return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
+}
+
+static int
+r535_dp_aux_xfer(struct nvkm_outp *outp, u8 type, u32 addr, u8 *data, u8 *psize)
+{
+ struct nvkm_disp *disp = outp->disp;
+ NV0073_CTRL_DP_AUXCH_CTRL_PARAMS *ctrl;
+ u8 size = *psize;
+ int ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DP_AUXCH_CTRL, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(outp->index);
+ ctrl->bAddrOnly = !size;
+ ctrl->cmd = type;
+ if (ctrl->bAddrOnly) {
+ ctrl->cmd = NVDEF_SET(ctrl->cmd, NV0073_CTRL, DP_AUXCH_CMD, REQ_TYPE, WRITE);
+ ctrl->cmd = NVDEF_SET(ctrl->cmd, NV0073_CTRL, DP_AUXCH_CMD, I2C_MOT, FALSE);
+ }
+ ctrl->addr = addr;
+ ctrl->size = !ctrl->bAddrOnly ? (size - 1) : 0;
+ memcpy(ctrl->data, data, size);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return PTR_ERR(ctrl);
+ }
+
+ memcpy(data, ctrl->data, size);
+ *psize = ctrl->size;
+ ret = ctrl->replyType;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+}
+
+static int
+r535_dp_aux_pwr(struct nvkm_outp *outp, bool pu)
+{
+ return 0;
+}
+
+static void
+r535_dp_release(struct nvkm_outp *outp)
+{
+ if (!outp->dp.lt.bw) {
+ if (!WARN_ON(!outp->dp.rates))
+ outp->dp.lt.bw = outp->dp.rate[0].rate / 27000;
+ else
+ outp->dp.lt.bw = 0x06;
+ }
+
+ outp->dp.lt.nr = 0;
+
+ r535_dp_train_target(outp, 0, outp->dp.lt.mst, outp->dp.lt.nr, outp->dp.lt.bw);
+ r535_outp_release(outp);
+}
+
+static int
+r535_dp_acquire(struct nvkm_outp *outp, bool hda)
+{
+ int ret;
+
+ ret = r535_outp_acquire(outp, hda);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct nvkm_outp_func
+r535_dp = {
+ .detect = r535_outp_detect,
+ .inherit = r535_outp_inherit,
+ .acquire = r535_dp_acquire,
+ .release = r535_dp_release,
+ .dp.aux_pwr = r535_dp_aux_pwr,
+ .dp.aux_xfer = r535_dp_aux_xfer,
+ .dp.mst_id_get = r535_dp_mst_id_get,
+ .dp.mst_id_put = r535_dp_mst_id_put,
+ .dp.rates = r535_dp_rates,
+ .dp.train = r535_dp_train,
+ .dp.drive = r535_dp_drive,
+};
+
+static int
+r535_tmds_edid_get(struct nvkm_outp *outp, u8 *data, u16 *psize)
+{
+ NV0073_CTRL_SPECIFIC_GET_EDID_V2_PARAMS *ctrl;
+ struct nvkm_disp *disp = outp->disp;
+ int ret = -E2BIG;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_GET_EDID_V2, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(outp->index);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ ret = -E2BIG;
+ if (ctrl->bufferSize <= *psize) {
+ memcpy(data, ctrl->edidBuffer, ctrl->bufferSize);
+ *psize = ctrl->bufferSize;
+ ret = 0;
+ }
+
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+}
+
+static const struct nvkm_outp_func
+r535_tmds = {
+ .detect = r535_outp_detect,
+ .inherit = r535_outp_inherit,
+ .acquire = r535_outp_acquire,
+ .release = r535_outp_release,
+ .edid_get = r535_tmds_edid_get,
+};
+
+static int
+r535_outp_new(struct nvkm_disp *disp, u32 id)
+{
+ NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS *ctrl;
+ enum nvkm_ior_proto proto;
+ struct dcb_output dcbE = {};
+ struct nvkm_conn *conn;
+ struct nvkm_outp *outp;
+ u8 locn, link = 0;
+ int ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->subDeviceInstance = 0;
+ ctrl->displayId = BIT(id);
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ switch (ctrl->type) {
+ case NV0073_CTRL_SPECIFIC_OR_TYPE_NONE:
+ return 0;
+ case NV0073_CTRL_SPECIFIC_OR_TYPE_SOR:
+ switch (ctrl->protocol) {
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A:
+ proto = TMDS;
+ link = 1;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B:
+ proto = TMDS;
+ link = 2;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS:
+ proto = TMDS;
+ link = 3;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A:
+ proto = DP;
+ link = 1;
+ break;
+ case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B:
+ proto = DP;
+ link = 2;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ locn = ctrl->location;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ conn = r535_conn_new(disp, id);
+ if (IS_ERR(conn))
+ return PTR_ERR(conn);
+
+ switch (proto) {
+ case TMDS: dcbE.type = DCB_OUTPUT_TMDS; break;
+ case DP: dcbE.type = DCB_OUTPUT_DP; break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ dcbE.location = locn;
+ dcbE.connector = conn->index;
+ dcbE.heads = disp->head.mask;
+ dcbE.i2c_index = 0xff;
+ dcbE.link = dcbE.sorconf.link = link;
+
+ if (proto == TMDS) {
+ ret = nvkm_outp_new_(&r535_tmds, disp, id, &dcbE, &outp);
+ if (ret)
+ return ret;
+ } else {
+ NV0073_CTRL_CMD_DP_GET_CAPS_PARAMS *ctrl;
+ bool mst, wm;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_GET_CAPS, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->sorIndex = ~0;
+
+ ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
+ if (ret) {
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ return ret;
+ }
+
+ switch (NVVAL_GET(ctrl->maxLinkRate, NV0073_CTRL_CMD, DP_GET_CAPS, MAX_LINK_RATE)) {
+ case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_1_62:
+ dcbE.dpconf.link_bw = 0x06;
+ break;
+ case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_2_70:
+ dcbE.dpconf.link_bw = 0x0a;
+ break;
+ case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_5_40:
+ dcbE.dpconf.link_bw = 0x14;
+ break;
+ case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_8_10:
+ dcbE.dpconf.link_bw = 0x1e;
+ break;
+ default:
+ dcbE.dpconf.link_bw = 0x00;
+ break;
+ }
+
+ mst = ctrl->bIsMultistreamSupported;
+ wm = ctrl->bHasIncreasedWatermarkLimits;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ if (WARN_ON(!dcbE.dpconf.link_bw))
+ return -EINVAL;
+
+ dcbE.dpconf.link_nr = 4;
+
+ ret = nvkm_outp_new_(&r535_dp, disp, id, &dcbE, &outp);
+ if (ret)
+ return ret;
+
+ outp->dp.mst = mst;
+ outp->dp.increased_wm = wm;
+ }
+
+
+ outp->conn = conn;
+ list_add_tail(&outp->head, &disp->outps);
+ return 0;
+}
+
+static void
+r535_disp_irq(struct nvkm_gsp_event *event, void *repv, u32 repc)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), rm.irq);
+ Nv2080DpIrqNotification *irq = repv;
+
+ if (WARN_ON(repc < sizeof(*irq)))
+ return;
+
+ nvkm_debug(&disp->engine.subdev, "event: dp irq displayId %08x\n", irq->displayId);
+
+ if (irq->displayId)
+ nvkm_event_ntfy(&disp->rm.event, fls(irq->displayId) - 1, NVKM_DPYID_IRQ);
+}
+
+static void
+r535_disp_hpd(struct nvkm_gsp_event *event, void *repv, u32 repc)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), rm.hpd);
+ Nv2080HotplugNotification *hpd = repv;
+
+ if (WARN_ON(repc < sizeof(*hpd)))
+ return;
+
+ nvkm_debug(&disp->engine.subdev, "event: hpd plug %08x unplug %08x\n",
+ hpd->plugDisplayMask, hpd->unplugDisplayMask);
+
+ for (int i = 0; i < 31; i++) {
+ u32 mask = 0;
+
+ if (hpd->plugDisplayMask & BIT(i))
+ mask |= NVKM_DPYID_PLUG;
+ if (hpd->unplugDisplayMask & BIT(i))
+ mask |= NVKM_DPYID_UNPLUG;
+
+ if (mask)
+ nvkm_event_ntfy(&disp->rm.event, i, mask);
+ }
+}
+
+static const struct nvkm_event_func
+r535_disp_event = {
+};
+
+static void
+r535_disp_intr_head_timing(struct nvkm_disp *disp, int head)
+{
+ struct nvkm_subdev *subdev = &disp->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ u32 stat = nvkm_rd32(device, 0x611c00 + (head * 0x04));
+
+ if (stat & 0x00000002) {
+ nvkm_disp_vblank(disp, head);
+
+ nvkm_wr32(device, 0x611800 + (head * 0x04), 0x00000002);
+ }
+}
+
+static irqreturn_t
+r535_disp_intr(struct nvkm_inth *inth)
+{
+ struct nvkm_disp *disp = container_of(inth, typeof(*disp), engine.subdev.inth);
+ struct nvkm_subdev *subdev = &disp->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ unsigned long mask = nvkm_rd32(device, 0x611ec0) & 0x000000ff;
+ int head;
+
+ for_each_set_bit(head, &mask, 8)
+ r535_disp_intr_head_timing(disp, head);
+
+ return IRQ_HANDLED;
+}
+
+static void
+r535_disp_fini(struct nvkm_disp *disp, bool suspend)
+{
+ if (!disp->engine.subdev.use.enabled)
+ return;
+
+ nvkm_gsp_rm_free(&disp->rm.object);
+
+ if (!suspend) {
+ nvkm_gsp_event_dtor(&disp->rm.irq);
+ nvkm_gsp_event_dtor(&disp->rm.hpd);
+ nvkm_event_fini(&disp->rm.event);
+
+ nvkm_gsp_rm_free(&disp->rm.objcom);
+ nvkm_gsp_device_dtor(&disp->rm.device);
+ nvkm_gsp_client_dtor(&disp->rm.client);
+ }
+}
+
+static int
+r535_disp_init(struct nvkm_disp *disp)
+{
+ int ret;
+
+ ret = nvkm_gsp_rm_alloc(&disp->rm.device.object, disp->func->root.oclass << 16,
+ disp->func->root.oclass, 0, &disp->rm.object);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+r535_disp_oneinit(struct nvkm_disp *disp)
+{
+ struct nvkm_device *device = disp->engine.subdev.device;
+ struct nvkm_gsp *gsp = device->gsp;
+ NV2080_CTRL_INTERNAL_DISPLAY_WRITE_INST_MEM_PARAMS *ctrl;
+ int ret, i;
+
+ /* RAMIN. */
+ ret = nvkm_gpuobj_new(device, 0x10000, 0x10000, false, NULL, &disp->inst);
+ if (ret)
+ return ret;
+
+ if (WARN_ON(nvkm_memory_target(disp->inst->memory) != NVKM_MEM_TARGET_VRAM))
+ return -EINVAL;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_WRITE_INST_MEM,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->instMemPhysAddr = nvkm_memory_addr(disp->inst->memory);
+ ctrl->instMemSize = nvkm_memory_size(disp->inst->memory);
+ ctrl->instMemAddrSpace = ADDR_FBMEM;
+ ctrl->instMemCpuCacheAttr = NV_MEMORY_WRITECOMBINED;
+
+ ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
+ if (ret)
+ return ret;
+
+ /* OBJs. */
+ ret = nvkm_gsp_client_device_ctor(gsp, &disp->rm.client, &disp->rm.device);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gsp_rm_alloc(&disp->rm.device.object, 0x00730000, NV04_DISPLAY_COMMON, 0,
+ &disp->rm.objcom);
+ if (ret)
+ return ret;
+
+ {
+ NV2080_CTRL_INTERNAL_DISPLAY_GET_STATIC_INFO_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_GET_STATIC_INFO,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ disp->wndw.mask = ctrl->windowPresentMask;
+ disp->wndw.nr = fls(disp->wndw.mask);
+ nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);
+ }
+
+ /* */
+ {
+#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
+ NV2080_CTRL_INTERNAL_INIT_BRIGHTC_STATE_LOAD_PARAMS *ctrl;
+ struct nvkm_gsp_object *subdevice = &disp->rm.client.gsp->internal.device.subdevice;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(subdevice,
+ NV2080_CTRL_CMD_INTERNAL_INIT_BRIGHTC_STATE_LOAD,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->status = 0x56; /* NV_ERR_NOT_SUPPORTED */
+
+ {
+ const guid_t NBCI_DSM_GUID =
+ GUID_INIT(0xD4A50B75, 0x65C7, 0x46F7,
+ 0xBF, 0xB7, 0x41, 0x51, 0x4C, 0xEA, 0x02, 0x44);
+ u64 NBCI_DSM_REV = 0x00000102;
+ const guid_t NVHG_DSM_GUID =
+ GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
+ 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
+ u64 NVHG_DSM_REV = 0x00000102;
+ acpi_handle handle = ACPI_HANDLE(device->dev);
+
+ if (handle && acpi_has_method(handle, "_DSM")) {
+ bool nbci = acpi_check_dsm(handle, &NBCI_DSM_GUID, NBCI_DSM_REV,
+ 1ULL << 0x00000014);
+ bool nvhg = acpi_check_dsm(handle, &NVHG_DSM_GUID, NVHG_DSM_REV,
+ 1ULL << 0x00000014);
+
+ if (nbci || nvhg) {
+ union acpi_object argv4 = {
+ .buffer.type = ACPI_TYPE_BUFFER,
+ .buffer.length = sizeof(ctrl->backLightData),
+ .buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL),
+ }, *obj;
+
+ obj = acpi_evaluate_dsm(handle, nbci ? &NBCI_DSM_GUID : &NVHG_DSM_GUID,
+ 0x00000102, 0x14, &argv4);
+ if (!obj) {
+ acpi_handle_info(handle, "failed to evaluate _DSM\n");
+ } else {
+ for (int i = 0; i < obj->package.count; i++) {
+ union acpi_object *elt = &obj->package.elements[i];
+ u32 size;
+
+ if (elt->integer.value & ~0xffffffffULL)
+ size = 8;
+ else
+ size = 4;
+
+ memcpy(&ctrl->backLightData[ctrl->backLightDataSize], &elt->integer.value, size);
+ ctrl->backLightDataSize += size;
+ }
+
+ ctrl->status = 0;
+ ACPI_FREE(obj);
+ }
+
+ kfree(argv4.buffer.pointer);
+ }
+ }
+ }
+
+ ret = nvkm_gsp_rm_ctrl_wr(subdevice, ctrl);
+ if (ret)
+ return ret;
+#endif
+ }
+
+ /* */
+ {
+ NV0073_CTRL_CMD_DP_SET_MANUAL_DISPLAYPORT_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
+ NV0073_CTRL_CMD_DP_SET_MANUAL_DISPLAYPORT,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ret = nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
+ if (ret)
+ return ret;
+ }
+
+ /* */
+ {
+ NV0073_CTRL_SYSTEM_GET_NUM_HEADS_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SYSTEM_GET_NUM_HEADS, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ disp->head.nr = ctrl->numHeads;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+ }
+
+ /* */
+ {
+ NV0073_CTRL_SPECIFIC_GET_ALL_HEAD_MASK_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SPECIFIC_GET_ALL_HEAD_MASK,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ disp->head.mask = ctrl->headMask;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ for_each_set_bit(i, &disp->head.mask, disp->head.nr) {
+ ret = nvkm_head_new_(&r535_head, disp, i);
+ if (ret)
+ return ret;
+ }
+ }
+
+ disp->sor.nr = disp->func->sor.cnt(disp, &disp->sor.mask);
+ nvkm_debug(&disp->engine.subdev, " SOR(s): %d (%02lx)\n", disp->sor.nr, disp->sor.mask);
+ for_each_set_bit(i, &disp->sor.mask, disp->sor.nr) {
+ ret = disp->func->sor.new(disp, i);
+ if (ret)
+ return ret;
+ }
+
+ /* */
+ {
+ NV0073_CTRL_SYSTEM_GET_SUPPORTED_PARAMS *ctrl;
+ unsigned long mask;
+ int i;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
+ NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ mask = ctrl->displayMask;
+ nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
+
+ for_each_set_bit(i, &mask, 32) {
+ ret = r535_outp_new(disp, i);
+ if (ret)
+ return ret;
+ }
+ }
+
+ ret = nvkm_event_init(&r535_disp_event, &gsp->subdev, 3, 32, &disp->rm.event);
+ if (WARN_ON(ret))
+ return ret;
+
+ ret = nvkm_gsp_device_event_ctor(&disp->rm.device, 0x007e0000, NV2080_NOTIFIERS_HOTPLUG,
+ r535_disp_hpd, &disp->rm.hpd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gsp_device_event_ctor(&disp->rm.device, 0x007e0001, NV2080_NOTIFIERS_DP_IRQ,
+ r535_disp_irq, &disp->rm.irq);
+ if (ret)
+ return ret;
+
+ /* RAMHT. */
+ ret = nvkm_ramht_new(device, disp->func->ramht_size ? disp->func->ramht_size :
+ 0x1000, 0, disp->inst, &disp->ramht);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gsp_intr_stall(gsp, disp->engine.subdev.type, disp->engine.subdev.inst);
+ if (ret < 0)
+ return ret;
+
+ ret = nvkm_inth_add(&device->vfn->intr, ret, NVKM_INTR_PRIO_NORMAL, &disp->engine.subdev,
+ r535_disp_intr, &disp->engine.subdev.inth);
+ if (ret)
+ return ret;
+
+ nvkm_inth_allow(&disp->engine.subdev.inth);
+ return 0;
+}
+
+static void
+r535_disp_dtor(struct nvkm_disp *disp)
+{
+ kfree(disp->func);
+}
+
+int
+r535_disp_new(const struct nvkm_disp_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp)
+{
+ struct nvkm_disp_func *rm;
+ int ret;
+
+ if (!(rm = kzalloc(sizeof(*rm) + 6 * sizeof(rm->user[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_disp_dtor;
+ rm->oneinit = r535_disp_oneinit;
+ rm->init = r535_disp_init;
+ rm->fini = r535_disp_fini;
+ rm->uevent = hw->uevent;
+ rm->sor.cnt = r535_sor_cnt;
+ rm->sor.new = r535_sor_new;
+ rm->ramht_size = hw->ramht_size;
+
+ rm->root = hw->root;
+
+ for (int i = 0; hw->user[i].ctor; i++) {
+ switch (hw->user[i].base.oclass & 0xff) {
+ case 0x73: rm->user[i] = hw->user[i]; break;
+ case 0x7d: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_core; break;
+ case 0x7e: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_wndw; break;
+ case 0x7b: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_wimm; break;
+ case 0x7a: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_curs; break;
+ default:
+ WARN_ON(1);
+ continue;
+ }
+ }
+
+ ret = nvkm_disp_new_(rm, device, type, inst, pdisp);
+ if (ret)
+ kfree(rm);
+
+ mutex_init(&(*pdisp)->super.mutex); //XXX
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
index f5242a6722..dcb9f8ba37 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
@@ -25,6 +25,7 @@
#include "ior.h"
#include <core/gpuobj.h>
+#include <subdev/gsp.h>
#include <subdev/timer.h>
#include <nvif/class.h>
@@ -88,6 +89,7 @@ tu102_sor = {
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
+ .bl = &gt215_sor_bl,
.hdmi = &gv100_sor_hdmi,
.dp = &tu102_sor_dp,
.hda = &gv100_sor_hda,
@@ -232,5 +234,8 @@ int
tu102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_disp_new(&tu102_disp, device, type, inst, pdisp);
+
return nvkm_disp_new_(&tu102_disp, device, type, inst, pdisp);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
index 3249e5c1c8..2dab6612c4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
@@ -31,6 +31,23 @@
#include <nvif/if0011.h>
static int
+nvkm_uconn_uevent_gsp(struct nvkm_object *object, u64 token, u32 bits)
+{
+ union nvif_conn_event_args args;
+
+ args.v0.version = 0;
+ args.v0.types = 0;
+ if (bits & NVKM_DPYID_PLUG)
+ args.v0.types |= NVIF_CONN_EVENT_V0_PLUG;
+ if (bits & NVKM_DPYID_UNPLUG)
+ args.v0.types |= NVIF_CONN_EVENT_V0_UNPLUG;
+ if (bits & NVKM_DPYID_IRQ)
+ args.v0.types |= NVIF_CONN_EVENT_V0_IRQ;
+
+ return object->client->event(token, &args, sizeof(args.v0));
+}
+
+static int
nvkm_uconn_uevent_aux(struct nvkm_object *object, u64 token, u32 bits)
{
union nvif_conn_event_args args;
@@ -78,13 +95,14 @@ static int
nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
{
struct nvkm_conn *conn = nvkm_uconn(object);
- struct nvkm_device *device = conn->disp->engine.subdev.device;
+ struct nvkm_disp *disp = conn->disp;
+ struct nvkm_device *device = disp->engine.subdev.device;
struct nvkm_outp *outp;
union nvif_conn_event_args *args = argv;
u64 bits = 0;
if (!uevent) {
- if (conn->info.hpd == DCB_GPIO_UNUSED)
+ if (!disp->rm.client.gsp && conn->info.hpd == DCB_GPIO_UNUSED)
return -ENOSYS;
return 0;
}
@@ -100,6 +118,15 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_
if (&outp->head == &conn->disp->outps)
return -EINVAL;
+ if (disp->rm.client.gsp) {
+ if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_DPYID_PLUG;
+ if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_DPYID_UNPLUG;
+ if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_DPYID_IRQ;
+
+ return nvkm_uevent_add(uevent, &disp->rm.event, outp->index, bits,
+ nvkm_uconn_uevent_gsp);
+ }
+
if (outp->dp.aux && !outp->info.location) {
if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG;
if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG;
@@ -121,46 +148,6 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_
nvkm_uconn_uevent_gpio);
}
-static int
-nvkm_uconn_mthd_hpd_status(struct nvkm_conn *conn, void *argv, u32 argc)
-{
- struct nvkm_gpio *gpio = conn->disp->engine.subdev.device->gpio;
- union nvif_conn_hpd_status_args *args = argv;
-
- if (argc != sizeof(args->v0) || args->v0.version != 0)
- return -ENOSYS;
-
- args->v0.support = gpio && conn->info.hpd != DCB_GPIO_UNUSED;
- args->v0.present = 0;
-
- if (args->v0.support) {
- int ret = nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, conn->info.hpd);
-
- if (WARN_ON(ret < 0)) {
- args->v0.support = false;
- return 0;
- }
-
- args->v0.present = ret;
- }
-
- return 0;
-}
-
-static int
-nvkm_uconn_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
-{
- struct nvkm_conn *conn = nvkm_uconn(object);
-
- switch (mthd) {
- case NVIF_CONN_V0_HPD_STATUS: return nvkm_uconn_mthd_hpd_status(conn, argv, argc);
- default:
- break;
- }
-
- return -EINVAL;
-}
-
static void *
nvkm_uconn_dtor(struct nvkm_object *object)
{
@@ -176,7 +163,6 @@ nvkm_uconn_dtor(struct nvkm_object *object)
static const struct nvkm_object_func
nvkm_uconn = {
.dtor = nvkm_uconn_dtor,
- .mthd = nvkm_uconn_mthd,
.uevent = nvkm_uconn_uevent,
};
@@ -204,6 +190,32 @@ nvkm_uconn_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv
ret = -EBUSY;
spin_lock(&disp->client.lock);
if (!conn->object.func) {
+ switch (conn->info.type) {
+ case DCB_CONNECTOR_VGA : args->v0.type = NVIF_CONN_V0_VGA; break;
+ case DCB_CONNECTOR_TV_0 :
+ case DCB_CONNECTOR_TV_1 :
+ case DCB_CONNECTOR_TV_3 : args->v0.type = NVIF_CONN_V0_TV; break;
+ case DCB_CONNECTOR_DMS59_0 :
+ case DCB_CONNECTOR_DMS59_1 :
+ case DCB_CONNECTOR_DVI_I : args->v0.type = NVIF_CONN_V0_DVI_I; break;
+ case DCB_CONNECTOR_DVI_D : args->v0.type = NVIF_CONN_V0_DVI_D; break;
+ case DCB_CONNECTOR_LVDS : args->v0.type = NVIF_CONN_V0_LVDS; break;
+ case DCB_CONNECTOR_LVDS_SPWG: args->v0.type = NVIF_CONN_V0_LVDS_SPWG; break;
+ case DCB_CONNECTOR_DMS59_DP0:
+ case DCB_CONNECTOR_DMS59_DP1:
+ case DCB_CONNECTOR_DP :
+ case DCB_CONNECTOR_mDP :
+ case DCB_CONNECTOR_USB_C : args->v0.type = NVIF_CONN_V0_DP; break;
+ case DCB_CONNECTOR_eDP : args->v0.type = NVIF_CONN_V0_EDP; break;
+ case DCB_CONNECTOR_HDMI_0 :
+ case DCB_CONNECTOR_HDMI_1 :
+ case DCB_CONNECTOR_HDMI_C : args->v0.type = NVIF_CONN_V0_HDMI; break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ break;
+ }
+
nvkm_object_ctor(&nvkm_uconn, oclass, &conn->object);
*pobject = &conn->object;
ret = 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index fc283a4a15..377d0e0cef 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -25,6 +25,8 @@
#include "head.h"
#include "ior.h"
+#include <subdev/i2c.h>
+
#include <nvif/if0012.h>
static int
@@ -44,17 +46,121 @@ nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc)
}
static int
-nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp *outp, void *argv, u32 argc)
+nvkm_uoutp_mthd_dp_mst_id_put(struct nvkm_outp *outp, void *argv, u32 argc)
{
- union nvif_outp_dp_retrain_args *args = argv;
+ union nvif_outp_dp_mst_id_put_args *args = argv;
- if (argc != sizeof(args->vn))
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->dp.mst_id_put)
+ return -EINVAL;
+
+ return outp->func->dp.mst_id_put(outp, args->v0.id);
+}
+
+static int
+nvkm_uoutp_mthd_dp_mst_id_get(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_mst_id_get_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->dp.mst_id_get)
+ return -EINVAL;
+
+ return outp->func->dp.mst_id_get(outp, &args->v0.id);
+}
+
+static int
+nvkm_uoutp_mthd_dp_sst(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_sst_args *args = argv;
+ struct nvkm_disp *disp = outp->disp;
+ struct nvkm_ior *ior = outp->ior;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
- if (!atomic_read(&outp->dp.lt.done))
+ if (!ior->func->dp || !nvkm_head_find(disp, args->v0.head))
+ return -EINVAL;
+ if (!ior->func->dp->sst)
return 0;
- return outp->func->acquire(outp);
+ return ior->func->dp->sst(ior, args->v0.head,
+ outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP,
+ args->v0.watermark, args->v0.hblanksym, args->v0.vblanksym);
+}
+
+static int
+nvkm_uoutp_mthd_dp_drive(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_drive_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->dp.drive)
+ return -EINVAL;
+
+ return outp->func->dp.drive(outp, args->v0.lanes, args->v0.pe, args->v0.vs);
+}
+
+static int
+nvkm_uoutp_mthd_dp_train(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_train_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->dp.train)
+ return -EINVAL;
+
+ if (!args->v0.retrain) {
+ memcpy(outp->dp.dpcd, args->v0.dpcd, sizeof(outp->dp.dpcd));
+ outp->dp.lttprs = args->v0.lttprs;
+ outp->dp.lt.nr = args->v0.link_nr;
+ outp->dp.lt.bw = args->v0.link_bw / 27000;
+ outp->dp.lt.mst = args->v0.mst;
+ outp->dp.lt.post_adj = args->v0.post_lt_adj;
+ }
+
+ return outp->func->dp.train(outp, args->v0.retrain);
+}
+
+static int
+nvkm_uoutp_mthd_dp_rates(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_rates_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (args->v0.rates > ARRAY_SIZE(outp->dp.rate))
+ return -EINVAL;
+
+ for (int i = 0; i < args->v0.rates; i++) {
+ outp->dp.rate[i].dpcd = args->v0.rate[i].dpcd;
+ outp->dp.rate[i].rate = args->v0.rate[i].rate;
+ }
+
+ outp->dp.rates = args->v0.rates;
+
+ if (outp->func->dp.rates)
+ outp->func->dp.rates(outp);
+
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_dp_aux_xfer(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_aux_xfer_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->dp.aux_xfer)
+ return -EINVAL;
+
+ return outp->func->dp.aux_xfer(outp, args->v0.type, args->v0.addr,
+ args->v0.data, &args->v0.size);
}
static int
@@ -64,10 +170,10 @@ nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc)
if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
+ if (!outp->func->dp.aux_pwr)
+ return -EINVAL;
- outp->dp.enabled = !!args->v0.state;
- nvkm_dp_enable(outp, outp->dp.enabled);
- return 0;
+ return outp->func->dp.aux_pwr(outp, !!args->v0.state);
}
static int
@@ -88,12 +194,20 @@ nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc)
if (argc && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP)
ior->func->dp->audio(ior, args->v0.head, true);
+ else
+ if (ior->func->hdmi->audio)
+ ior->func->hdmi->audio(ior, args->v0.head, true);
+
ior->func->hda->hpd(ior, args->v0.head, true);
ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc);
} else {
+ ior->func->hda->hpd(ior, args->v0.head, false);
+
if (outp->info.type == DCB_OUTPUT_DP)
ior->func->dp->audio(ior, args->v0.head, false);
- ior->func->hda->hpd(ior, args->v0.head, false);
+ else
+ if (ior->func->hdmi->audio)
+ ior->func->hdmi->audio(ior, args->v0.head, false);
}
return 0;
@@ -126,84 +240,105 @@ nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc)
}
static int
-nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc)
+nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc)
{
- struct nvkm_head *head = outp->asy.head;
+ union nvif_outp_hdmi_args *args = argv;
struct nvkm_ior *ior = outp->ior;
- union nvif_outp_release_args *args = argv;
- if (argc != sizeof(args->vn))
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
- if (ior->func->hdmi && head) {
- ior->func->hdmi->infoframe_avi(ior, head->id, NULL, 0);
- ior->func->hdmi->infoframe_vsi(ior, head->id, NULL, 0);
- ior->func->hdmi->ctrl(ior, head->id, false, 0, 0);
+ if (!(outp->asy.head = nvkm_head_find(outp->disp, args->v0.head)))
+ return -EINVAL;
+
+ if (!ior->func->hdmi ||
+ args->v0.max_ac_packet > 0x1f ||
+ args->v0.rekey > 0x7f ||
+ (args->v0.scdc && !ior->func->hdmi->scdc))
+ return -EINVAL;
+
+ if (!args->v0.enable) {
+ ior->func->hdmi->infoframe_avi(ior, args->v0.head, NULL, 0);
+ ior->func->hdmi->infoframe_vsi(ior, args->v0.head, NULL, 0);
+ ior->func->hdmi->ctrl(ior, args->v0.head, false, 0, 0);
+ return 0;
}
- nvkm_outp_release(outp, NVKM_OUTP_USER);
+ ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable,
+ args->v0.max_ac_packet, args->v0.rekey);
+ if (ior->func->hdmi->scdc)
+ ior->func->hdmi->scdc(ior, args->v0.khz, args->v0.scdc, args->v0.scdc_scrambling,
+ args->v0.scdc_low_rates);
+
return 0;
}
static int
-nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE],
- u8 link_nr, u8 link_bw, bool hda, bool mst)
+nvkm_uoutp_mthd_lvds(struct nvkm_outp *outp, void *argv, u32 argc)
{
- int ret;
+ union nvif_outp_lvds_args *args = argv;
- ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda);
- if (ret)
- return ret;
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (outp->info.type != DCB_OUTPUT_LVDS)
+ return -EINVAL;
- memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd));
- outp->dp.lt.nr = link_nr;
- outp->dp.lt.bw = link_bw;
- outp->dp.lt.mst = mst;
+ outp->lvds.dual = !!args->v0.dual;
+ outp->lvds.bpc8 = !!args->v0.bpc8;
return 0;
}
static int
-nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet,
- u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda)
+nvkm_uoutp_mthd_bl_set(struct nvkm_outp *outp, void *argv, u32 argc)
{
- struct nvkm_ior *ior;
+ union nvif_outp_bl_get_args *args = argv;
int ret;
- if (!(outp->asy.head = nvkm_head_find(outp->disp, head)))
- return -EINVAL;
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
- ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hdmi && hdmi_hda);
- if (ret)
- return ret;
+ if (outp->func->bl.set)
+ ret = outp->func->bl.set(outp, args->v0.level);
+ else
+ ret = -EINVAL;
- ior = outp->ior;
+ return ret;
+}
- if (hdmi) {
- if (!ior->func->hdmi ||
- hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f ||
- (hdmi_scdc && !ior->func->hdmi->scdc)) {
- nvkm_outp_release(outp, NVKM_OUTP_USER);
- return -EINVAL;
- }
+static int
+nvkm_uoutp_mthd_bl_get(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_bl_get_args *args = argv;
+ int ret;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
- ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey);
- if (ior->func->hdmi->scdc)
- ior->func->hdmi->scdc(ior, hdmi_scdc);
+ if (outp->func->bl.get) {
+ ret = outp->func->bl.get(outp);
+ if (ret >= 0) {
+ args->v0.level = ret;
+ ret = 0;
+ }
+ } else {
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
static int
-nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8)
+nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc)
{
- if (outp->info.type != DCB_OUTPUT_LVDS)
- return -EINVAL;
+ union nvif_outp_release_args *args = argv;
- outp->lvds.dual = dual;
- outp->lvds.bpc8 = bpc8;
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+ if (!outp->ior)
+ return -EINVAL;
- return nvkm_outp_acquire(outp, NVKM_OUTP_USER, false);
+ outp->func->release(outp);
+ return 0;
}
static int
@@ -214,30 +349,16 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
- if (outp->ior)
+ if (outp->ior && args->v0.type <= NVIF_OUTP_ACQUIRE_V0_PIOR)
return -EBUSY;
- switch (args->v0.proto) {
- case NVIF_OUTP_ACQUIRE_V0_RGB_CRT:
- ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, false);
+ switch (args->v0.type) {
+ case NVIF_OUTP_ACQUIRE_V0_DAC:
+ case NVIF_OUTP_ACQUIRE_V0_PIOR:
+ ret = outp->func->acquire(outp, false);
break;
- case NVIF_OUTP_ACQUIRE_V0_TMDS:
- ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head,
- args->v0.tmds.hdmi,
- args->v0.tmds.hdmi_max_ac_packet,
- args->v0.tmds.hdmi_rekey,
- args->v0.tmds.hdmi_scdc,
- args->v0.tmds.hdmi_hda);
- break;
- case NVIF_OUTP_ACQUIRE_V0_LVDS:
- ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8);
- break;
- case NVIF_OUTP_ACQUIRE_V0_DP:
- ret = nvkm_uoutp_mthd_acquire_dp(outp, args->v0.dp.dpcd,
- args->v0.dp.link_nr,
- args->v0.dp.link_bw,
- args->v0.dp.hda != 0,
- args->v0.dp.mst != 0);
+ case NVIF_OUTP_ACQUIRE_V0_SOR:
+ ret = outp->func->acquire(outp, args->v0.sor.hda);
break;
default:
ret = -EINVAL;
@@ -253,6 +374,69 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
}
static int
+nvkm_uoutp_mthd_inherit(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_inherit_args *args = argv;
+ struct nvkm_ior *ior;
+ int ret = 0;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+
+ /* Ensure an ior is hooked up to this outp already */
+ ior = outp->func->inherit(outp);
+ if (!ior || !ior->arm.head)
+ return -ENODEV;
+
+ /* With iors, there will be a separate output path for each type of connector - and all of
+ * them will appear to be hooked up. Figure out which one is actually the one we're using
+ * based on the protocol we were given over nvif
+ */
+ switch (args->v0.proto) {
+ case NVIF_OUTP_INHERIT_V0_TMDS:
+ if (ior->arm.proto != TMDS)
+ return -ENODEV;
+ break;
+ case NVIF_OUTP_INHERIT_V0_DP:
+ if (ior->arm.proto != DP)
+ return -ENODEV;
+ break;
+ case NVIF_OUTP_INHERIT_V0_LVDS:
+ if (ior->arm.proto != LVDS)
+ return -ENODEV;
+ break;
+ case NVIF_OUTP_INHERIT_V0_TV:
+ if (ior->arm.proto != TV)
+ return -ENODEV;
+ break;
+ case NVIF_OUTP_INHERIT_V0_RGB_CRT:
+ if (ior->arm.proto != CRT)
+ return -ENODEV;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Make sure that userspace hasn't already acquired this */
+ if (outp->acquired) {
+ OUTP_ERR(outp, "cannot inherit an already acquired (%02x) outp", outp->acquired);
+ return -EBUSY;
+ }
+
+ /* Mark the outp acquired by userspace now that we've confirmed it's already active */
+ OUTP_TRACE(outp, "inherit %02x |= %02x %p", outp->acquired, NVKM_OUTP_USER, ior);
+ nvkm_outp_acquire_ior(outp, NVKM_OUTP_USER, ior);
+
+ args->v0.or = ior->id;
+ args->v0.link = ior->arm.link;
+ args->v0.head = ffs(ior->arm.head) - 1;
+ args->v0.proto = ior->arm.proto_evo;
+
+ return ret;
+}
+
+static int
nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
{
union nvif_outp_load_detect_args *args = argv;
@@ -261,7 +445,7 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
- ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV, false);
+ ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false);
if (ret == 0) {
if (outp->ior->func->sense) {
ret = outp->ior->func->sense(outp->ior, args->v0.data);
@@ -269,21 +453,64 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
} else {
ret = -EINVAL;
}
- nvkm_outp_release(outp, NVKM_OUTP_PRIV);
+ nvkm_outp_release_or(outp, NVKM_OUTP_PRIV);
}
return ret;
}
static int
+nvkm_uoutp_mthd_edid_get(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_edid_get_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->edid_get)
+ return -EINVAL;
+
+ args->v0.size = ARRAY_SIZE(args->v0.data);
+ return outp->func->edid_get(outp, args->v0.data, &args->v0.size);
+}
+
+static int
+nvkm_uoutp_mthd_detect(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_detect_args *args = argv;
+ int ret;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!outp->func->detect)
+ return -EINVAL;
+
+ ret = outp->func->detect(outp);
+ switch (ret) {
+ case 0: args->v0.status = NVIF_OUTP_DETECT_V0_NOT_PRESENT; break;
+ case 1: args->v0.status = NVIF_OUTP_DETECT_V0_PRESENT; break;
+ default:
+ args->v0.status = NVIF_OUTP_DETECT_V0_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int
nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
{
switch (mthd) {
- case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc);
- case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc);
- case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc);
- case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc);
- case NVIF_OUTP_V0_DP_MST_VCPI: return nvkm_uoutp_mthd_dp_mst_vcpi(outp, argv, argc);
+ case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc);
+ case NVIF_OUTP_V0_LVDS : return nvkm_uoutp_mthd_lvds (outp, argv, argc);
+ case NVIF_OUTP_V0_HDMI : return nvkm_uoutp_mthd_hdmi (outp, argv, argc);
+ case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc);
+ case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_TRAIN : return nvkm_uoutp_mthd_dp_train (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_DRIVE : return nvkm_uoutp_mthd_dp_drive (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_SST : return nvkm_uoutp_mthd_dp_sst (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_MST_ID_GET: return nvkm_uoutp_mthd_dp_mst_id_get(outp, argv, argc);
+ case NVIF_OUTP_V0_DP_MST_ID_PUT: return nvkm_uoutp_mthd_dp_mst_id_put(outp, argv, argc);
+ case NVIF_OUTP_V0_DP_MST_VCPI : return nvkm_uoutp_mthd_dp_mst_vcpi (outp, argv, argc);
default:
break;
}
@@ -292,17 +519,25 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
}
static int
-nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
+nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc, bool *invalid)
{
switch (mthd) {
- case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc);
+ case NVIF_OUTP_V0_DETECT : return nvkm_uoutp_mthd_detect (outp, argv, argc);
+ case NVIF_OUTP_V0_EDID_GET : return nvkm_uoutp_mthd_edid_get (outp, argv, argc);
+ case NVIF_OUTP_V0_INHERIT : return nvkm_uoutp_mthd_inherit (outp, argv, argc);
case NVIF_OUTP_V0_ACQUIRE : return nvkm_uoutp_mthd_acquire (outp, argv, argc);
+ case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc);
+ case NVIF_OUTP_V0_BL_GET : return nvkm_uoutp_mthd_bl_get (outp, argv, argc);
+ case NVIF_OUTP_V0_BL_SET : return nvkm_uoutp_mthd_bl_set (outp, argv, argc);
case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_AUX_XFER: return nvkm_uoutp_mthd_dp_aux_xfer(outp, argv, argc);
+ case NVIF_OUTP_V0_DP_RATES : return nvkm_uoutp_mthd_dp_rates (outp, argv, argc);
default:
break;
}
- return 1;
+ *invalid = true;
+ return 0;
}
static int
@@ -310,12 +545,13 @@ nvkm_uoutp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
{
struct nvkm_outp *outp = nvkm_uoutp(object);
struct nvkm_disp *disp = outp->disp;
+ bool invalid = false;
int ret;
mutex_lock(&disp->super.mutex);
- ret = nvkm_uoutp_mthd_noacquire(outp, mthd, argv, argc);
- if (ret <= 0)
+ ret = nvkm_uoutp_mthd_noacquire(outp, mthd, argv, argc, &invalid);
+ if (!invalid)
goto done;
if (outp->ior)
@@ -370,10 +606,60 @@ nvkm_uoutp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv
ret = -EBUSY;
spin_lock(&disp->client.lock);
if (!outp->object.func) {
+ switch (outp->info.type) {
+ case DCB_OUTPUT_ANALOG:
+ args->v0.type = NVIF_OUTP_V0_TYPE_DAC;
+ args->v0.proto = NVIF_OUTP_V0_PROTO_RGB_CRT;
+ args->v0.rgb_crt.freq_max = outp->info.crtconf.maxfreq;
+ break;
+ case DCB_OUTPUT_TMDS:
+ if (!outp->info.location) {
+ args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
+ args->v0.tmds.dual = (outp->info.tmdsconf.sor.link == 3);
+ } else {
+ args->v0.type = NVIF_OUTP_V0_TYPE_PIOR;
+ args->v0.tmds.dual = 0;
+ }
+ args->v0.proto = NVIF_OUTP_V0_PROTO_TMDS;
+ break;
+ case DCB_OUTPUT_LVDS:
+ args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
+ args->v0.proto = NVIF_OUTP_V0_PROTO_LVDS;
+ args->v0.lvds.acpi_edid = outp->info.lvdsconf.use_acpi_for_edid;
+ break;
+ case DCB_OUTPUT_DP:
+ if (!outp->info.location) {
+ args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
+ args->v0.dp.aux = outp->info.i2c_index;
+ } else {
+ args->v0.type = NVIF_OUTP_V0_TYPE_PIOR;
+ args->v0.dp.aux = NVKM_I2C_AUX_EXT(outp->info.extdev);
+ }
+ args->v0.proto = NVIF_OUTP_V0_PROTO_DP;
+ args->v0.dp.mst = outp->dp.mst;
+ args->v0.dp.increased_wm = outp->dp.increased_wm;
+ args->v0.dp.link_nr = outp->info.dpconf.link_nr;
+ args->v0.dp.link_bw = outp->info.dpconf.link_bw * 27000;
+ break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (outp->info.location)
+ args->v0.ddc = NVKM_I2C_BUS_EXT(outp->info.extdev);
+ else
+ args->v0.ddc = outp->info.i2c_index;
+ args->v0.heads = outp->info.heads;
+ args->v0.conn = outp->info.connector;
+
nvkm_object_ctor(&nvkm_uoutp, oclass, &outp->object);
*pobject = &outp->object;
ret = 0;
}
+
+done:
spin_unlock(&disp->client.lock);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
index d619b40a42..fd5ee9f0af 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
@@ -318,14 +318,14 @@ nvkm_falcon_init(struct nvkm_engine *engine)
}
static void *
-nvkm_falcon_dtor(struct nvkm_engine *engine)
+nvkm_falcon_dtor_engine(struct nvkm_engine *engine)
{
return nvkm_falcon(engine);
}
static const struct nvkm_engine_func
nvkm_falcon = {
- .dtor = nvkm_falcon_dtor,
+ .dtor = nvkm_falcon_dtor_engine,
.oneinit = nvkm_falcon_oneinit,
.init = nvkm_falcon_init,
.fini = nvkm_falcon_fini,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
index 5a074b9970..aff92848ab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
@@ -26,5 +26,7 @@ nvkm-y += nvkm/engine/fifo/tu102.o
nvkm-y += nvkm/engine/fifo/ga100.o
nvkm-y += nvkm/engine/fifo/ga102.o
+nvkm-y += nvkm/engine/fifo/r535.o
+
nvkm-y += nvkm/engine/fifo/ucgrp.o
nvkm-y += nvkm/engine/fifo/uchan.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
index 5db37247dc..22443fe4a3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
@@ -210,6 +210,8 @@ nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
CASE(SEC2 );
CASE(NVDEC );
CASE(NVENC );
+ CASE(NVJPG );
+ CASE(OFA );
default:
WARN_ON(1);
break;
@@ -347,8 +349,14 @@ nvkm_fifo_dtor(struct nvkm_engine *engine)
nvkm_chid_unref(&fifo->cgid);
nvkm_chid_unref(&fifo->chid);
+ mutex_destroy(&fifo->userd.mutex);
+
nvkm_event_fini(&fifo->nonstall.event);
mutex_destroy(&fifo->mutex);
+
+ if (fifo->func->dtor)
+ fifo->func->dtor(fifo);
+
return fifo;
}
@@ -383,5 +391,8 @@ nvkm_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device,
spin_lock_init(&fifo->lock);
mutex_init(&fifo->mutex);
+ INIT_LIST_HEAD(&fifo->userd.list);
+ mutex_init(&fifo->userd.mutex);
+
return nvkm_engine_ctor(&nvkm_fifo, device, type, inst, true, &fifo->engine);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c
index ea53fb3d5d..814db9daa1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c
@@ -156,6 +156,9 @@ nvkm_cgrp_vctx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_c
atomic_inc(&vctx->vmm->engref[engn->engine->subdev.type]);
/* Allocate the HW structures. */
+ if (engn->func->ctor2) {
+ ret = engn->func->ctor2(engn, vctx, chan);
+ } else
if (engn->func->bind) {
ret = nvkm_object_bind(vctx->ectx->object, NULL, 0, &vctx->inst);
if (ret == 0 && engn->func->ctor)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
index b7c9d6115b..87a62d4ff4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
@@ -275,13 +275,17 @@ nvkm_chan_del(struct nvkm_chan **pchan)
nvkm_gpuobj_del(&chan->cache);
nvkm_gpuobj_del(&chan->ramfc);
- nvkm_memory_unref(&chan->userd.mem);
-
if (chan->cgrp) {
- nvkm_chid_put(chan->cgrp->runl->chid, chan->id, &chan->cgrp->lock);
+ if (!chan->func->id_put)
+ nvkm_chid_put(chan->cgrp->runl->chid, chan->id, &chan->cgrp->lock);
+ else
+ chan->func->id_put(chan);
+
nvkm_cgrp_unref(&chan->cgrp);
}
+ nvkm_memory_unref(&chan->userd.mem);
+
if (chan->vmm) {
nvkm_vmm_part(chan->vmm, chan->inst->memory);
nvkm_vmm_unref(&chan->vmm);
@@ -438,7 +442,32 @@ nvkm_chan_new_(const struct nvkm_chan_func *func, struct nvkm_runl *runl, int ru
}
/* Allocate channel ID. */
- chan->id = nvkm_chid_get(runl->chid, chan);
+ if (!chan->func->id_get) {
+ chan->id = nvkm_chid_get(runl->chid, chan);
+ if (chan->id >= 0) {
+ if (func->userd->bar < 0) {
+ if (ouserd + chan->func->userd->size >=
+ nvkm_memory_size(userd)) {
+ RUNL_DEBUG(runl, "ouserd %llx", ouserd);
+ return -EINVAL;
+ }
+
+ ret = nvkm_memory_kmap(userd, &chan->userd.mem);
+ if (ret) {
+ RUNL_DEBUG(runl, "userd %d", ret);
+ return ret;
+ }
+
+ chan->userd.base = ouserd;
+ } else {
+ chan->userd.mem = nvkm_memory_ref(fifo->userd.mem);
+ chan->userd.base = chan->id * chan->func->userd->size;
+ }
+ }
+ } else {
+ chan->id = chan->func->id_get(chan, userd, ouserd);
+ }
+
if (chan->id < 0) {
RUNL_ERROR(runl, "!chids");
return -ENOSPC;
@@ -448,24 +477,6 @@ nvkm_chan_new_(const struct nvkm_chan_func *func, struct nvkm_runl *runl, int ru
cgrp->id = chan->id;
/* Initialise USERD. */
- if (func->userd->bar < 0) {
- if (ouserd + chan->func->userd->size >= nvkm_memory_size(userd)) {
- RUNL_DEBUG(runl, "ouserd %llx", ouserd);
- return -EINVAL;
- }
-
- ret = nvkm_memory_kmap(userd, &chan->userd.mem);
- if (ret) {
- RUNL_DEBUG(runl, "userd %d", ret);
- return ret;
- }
-
- chan->userd.base = ouserd;
- } else {
- chan->userd.mem = nvkm_memory_ref(fifo->userd.mem);
- chan->userd.base = chan->id * chan->func->userd->size;
- }
-
if (chan->func->userd->clear)
chan->func->userd->clear(chan);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
index 85b94f6991..013682a709 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
@@ -17,6 +17,9 @@ struct nvkm_cctx {
};
struct nvkm_chan_func {
+ int (*id_get)(struct nvkm_chan *, struct nvkm_memory *userd, u64 ouserd);
+ void (*id_put)(struct nvkm_chan *);
+
const struct nvkm_chan_func_inst {
u32 size;
bool zero;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
index c56d2a839e..e74493a456 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
@@ -27,6 +27,7 @@
#include "runq.h"
#include <core/gpuobj.h>
+#include <subdev/gsp.h>
#include <subdev/top.h>
#include <subdev/vfn.h>
@@ -549,6 +550,10 @@ ga100_fifo_nonstall_ctor(struct nvkm_fifo *fifo)
struct nvkm_engn *engn = list_first_entry(&runl->engns, typeof(*engn), head);
runl->nonstall.vector = engn->func->nonstall(engn);
+
+ /* if no nonstall vector just keep going */
+ if (runl->nonstall.vector == -1)
+ continue;
if (runl->nonstall.vector < 0) {
RUNL_ERROR(runl, "nonstall %d", runl->nonstall.vector);
return runl->nonstall.vector;
@@ -607,5 +612,8 @@ int
ga100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_fifo_new(&ga100_fifo, device, type, inst, pfifo);
+
return nvkm_fifo_new_(&ga100_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c
index 2cdf5da339..755235f55b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c
@@ -21,6 +21,8 @@
*/
#include "priv.h"
+#include <subdev/gsp.h>
+
#include <nvif/class.h>
static const struct nvkm_fifo_func
@@ -34,12 +36,15 @@ ga102_fifo = {
.engn = &ga100_engn,
.engn_ce = &ga100_engn_ce,
.cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &ga100_cgrp, .force = true },
- .chan = {{ 0, 0, AMPERE_CHANNEL_GPFIFO_B }, &ga100_chan },
+ .chan = {{ 0, 0, AMPERE_CHANNEL_GPFIFO_A }, &ga100_chan },
};
int
ga102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_fifo_new(&ga102_fifo, device, type, inst, pfifo);
+
return nvkm_fifo_new_(&ga102_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
index 4d448be192..a0f3277605 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
@@ -13,6 +13,8 @@ struct nvkm_runq;
struct nvkm_vctx;
struct nvkm_fifo_func {
+ void (*dtor)(struct nvkm_fifo *);
+
int (*chid_nr)(struct nvkm_fifo *);
int (*chid_ctor)(struct nvkm_fifo *, int nr);
int (*runq_nr)(struct nvkm_fifo *);
@@ -58,6 +60,8 @@ struct nvkm_fifo_func {
} chan;
};
+int r535_fifo_new(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
+ struct nvkm_fifo **);
int nvkm_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_fifo **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c
new file mode 100644
index 0000000000..3454c7d295
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright 2023 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 "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+
+#include <core/gpuobj.h>
+#include <subdev/gsp.h>
+#include <subdev/mmu.h>
+#include <subdev/vfn.h>
+#include <engine/gr.h>
+
+#include <nvhw/drf.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/alloc/alloc_channel.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/class/cl2080_notification.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080ce.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080fifo.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080gpu.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080internal.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrla06f/ctrla06fgpfifo.h>
+#include <nvrm/535.113.01/nvidia/generated/g_kernel_channel_nvoc.h>
+#include <nvrm/535.113.01/nvidia/generated/g_kernel_fifo_nvoc.h>
+#include <nvrm/535.113.01/nvidia/inc/kernel/gpu/gpu_engine_type.h>
+
+static u32
+r535_chan_doorbell_handle(struct nvkm_chan *chan)
+{
+ return (chan->cgrp->runl->id << 16) | chan->id;
+}
+
+static void
+r535_chan_stop(struct nvkm_chan *chan)
+{
+}
+
+static void
+r535_chan_start(struct nvkm_chan *chan)
+{
+}
+
+static void
+r535_chan_ramfc_clear(struct nvkm_chan *chan)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+
+ nvkm_gsp_rm_free(&chan->rm.object);
+
+ dma_free_coherent(fifo->engine.subdev.device->dev, fifo->rm.mthdbuf_size,
+ chan->rm.mthdbuf.ptr, chan->rm.mthdbuf.addr);
+
+ nvkm_cgrp_vctx_put(chan->cgrp, &chan->rm.grctx);
+}
+
+#define CHID_PER_USERD 8
+
+static int
+r535_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ struct nvkm_engn *engn;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ NV_CHANNELGPFIFO_ALLOCATION_PARAMETERS *args;
+ const int userd_p = chan->id / CHID_PER_USERD;
+ const int userd_i = chan->id % CHID_PER_USERD;
+ u32 eT = ~0;
+ int ret;
+
+ if (unlikely(device->gr && !device->gr->engine.subdev.oneinit)) {
+ ret = nvkm_subdev_oneinit(&device->gr->engine.subdev);
+ if (ret)
+ return ret;
+ }
+
+ nvkm_runl_foreach_engn(engn, chan->cgrp->runl) {
+ eT = engn->id;
+ break;
+ }
+
+ if (WARN_ON(eT == ~0))
+ return -EINVAL;
+
+ chan->rm.mthdbuf.ptr = dma_alloc_coherent(fifo->engine.subdev.device->dev,
+ fifo->rm.mthdbuf_size,
+ &chan->rm.mthdbuf.addr, GFP_KERNEL);
+ if (!chan->rm.mthdbuf.ptr)
+ return -ENOMEM;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->vmm->rm.device.object, 0xf1f00000 | chan->id,
+ fifo->func->chan.user.oclass, sizeof(*args),
+ &chan->rm.object);
+ if (WARN_ON(IS_ERR(args)))
+ return PTR_ERR(args);
+
+ args->gpFifoOffset = offset;
+ args->gpFifoEntries = length / 8;
+
+ args->flags = NVDEF(NVOS04, FLAGS, CHANNEL_TYPE, PHYSICAL);
+ args->flags |= NVDEF(NVOS04, FLAGS, VPR, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_SKIP_MAP_REFCOUNTING, FALSE);
+ args->flags |= NVVAL(NVOS04, FLAGS, GROUP_CHANNEL_RUNQUEUE, chan->runq);
+ if (!priv)
+ args->flags |= NVDEF(NVOS04, FLAGS, PRIVILEGED_CHANNEL, FALSE);
+ else
+ args->flags |= NVDEF(NVOS04, FLAGS, PRIVILEGED_CHANNEL, TRUE);
+ args->flags |= NVDEF(NVOS04, FLAGS, DELAY_CHANNEL_SCHEDULING, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_DENY_PHYSICAL_MODE_CE, FALSE);
+
+ args->flags |= NVVAL(NVOS04, FLAGS, CHANNEL_USERD_INDEX_VALUE, userd_i);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_USERD_INDEX_FIXED, FALSE);
+ args->flags |= NVVAL(NVOS04, FLAGS, CHANNEL_USERD_INDEX_PAGE_VALUE, userd_p);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_USERD_INDEX_PAGE_FIXED, TRUE);
+
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_DENY_AUTH_LEVEL_PRIV, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_SKIP_SCRUBBER, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_CLIENT_MAP_FIFO, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, SET_EVICT_LAST_CE_PREFETCH_CHANNEL, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_VGPU_PLUGIN_CONTEXT, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, CHANNEL_PBDMA_ACQUIRE_TIMEOUT, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, GROUP_CHANNEL_THREAD, DEFAULT);
+ args->flags |= NVDEF(NVOS04, FLAGS, MAP_CHANNEL, FALSE);
+ args->flags |= NVDEF(NVOS04, FLAGS, SKIP_CTXBUFFER_ALLOC, FALSE);
+
+ args->hVASpace = chan->vmm->rm.object.handle;
+ args->engineType = eT;
+
+ args->instanceMem.base = chan->inst->addr;
+ args->instanceMem.size = chan->inst->size;
+ args->instanceMem.addressSpace = 2;
+ args->instanceMem.cacheAttrib = 1;
+
+ args->userdMem.base = nvkm_memory_addr(chan->userd.mem) + chan->userd.base;
+ args->userdMem.size = fifo->func->chan.func->userd->size;
+ args->userdMem.addressSpace = 2;
+ args->userdMem.cacheAttrib = 1;
+
+ args->ramfcMem.base = chan->inst->addr + 0;
+ args->ramfcMem.size = 0x200;
+ args->ramfcMem.addressSpace = 2;
+ args->ramfcMem.cacheAttrib = 1;
+
+ args->mthdbufMem.base = chan->rm.mthdbuf.addr;
+ args->mthdbufMem.size = fifo->rm.mthdbuf_size;
+ args->mthdbufMem.addressSpace = 1;
+ args->mthdbufMem.cacheAttrib = 0;
+
+ if (!priv)
+ args->internalFlags = NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, PRIVILEGE, USER);
+ else
+ args->internalFlags = NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, PRIVILEGE, ADMIN);
+ args->internalFlags |= NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, ERROR_NOTIFIER_TYPE, NONE);
+ args->internalFlags |= NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, ECC_ERROR_NOTIFIER_TYPE, NONE);
+
+ ret = nvkm_gsp_rm_alloc_wr(&chan->rm.object, args);
+ if (ret)
+ return ret;
+
+ if (1) {
+ NVA06F_CTRL_GPFIFO_SCHEDULE_PARAMS *ctrl;
+
+ if (1) {
+ NVA06F_CTRL_BIND_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&chan->rm.object,
+ NVA06F_CTRL_CMD_BIND, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return PTR_ERR(ctrl);
+
+ ctrl->engineType = eT;
+
+ ret = nvkm_gsp_rm_ctrl_wr(&chan->rm.object, ctrl);
+ if (ret)
+ return ret;
+ }
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&chan->rm.object,
+ NVA06F_CTRL_CMD_GPFIFO_SCHEDULE, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return PTR_ERR(ctrl);
+
+ ctrl->bEnable = 1;
+ ret = nvkm_gsp_rm_ctrl_wr(&chan->rm.object, ctrl);
+ }
+
+ return ret;
+}
+
+static const struct nvkm_chan_func_ramfc
+r535_chan_ramfc = {
+ .write = r535_chan_ramfc_write,
+ .clear = r535_chan_ramfc_clear,
+ .devm = 0xfff,
+ .priv = true,
+};
+
+struct r535_chan_userd {
+ struct nvkm_memory *mem;
+ struct nvkm_memory *map;
+ int chid;
+ u32 used;
+
+ struct list_head head;
+} *userd;
+
+static void
+r535_chan_id_put(struct nvkm_chan *chan)
+{
+ struct nvkm_runl *runl = chan->cgrp->runl;
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct r535_chan_userd *userd;
+
+ mutex_lock(&fifo->userd.mutex);
+ list_for_each_entry(userd, &fifo->userd.list, head) {
+ if (userd->map == chan->userd.mem) {
+ u32 chid = chan->userd.base / chan->func->userd->size;
+
+ userd->used &= ~BIT(chid);
+ if (!userd->used) {
+ nvkm_memory_unref(&userd->map);
+ nvkm_memory_unref(&userd->mem);
+ nvkm_chid_put(runl->chid, userd->chid, &chan->cgrp->lock);
+ list_del(&userd->head);
+ kfree(userd);
+ }
+
+ break;
+ }
+ }
+ mutex_unlock(&fifo->userd.mutex);
+
+}
+
+static int
+r535_chan_id_get_locked(struct nvkm_chan *chan, struct nvkm_memory *muserd, u64 ouserd)
+{
+ const u32 userd_size = CHID_PER_USERD * chan->func->userd->size;
+ struct nvkm_runl *runl = chan->cgrp->runl;
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct r535_chan_userd *userd;
+ u32 chid;
+ int ret;
+
+ if (ouserd + chan->func->userd->size >= userd_size ||
+ (ouserd & (chan->func->userd->size - 1))) {
+ RUNL_DEBUG(runl, "ouserd %llx", ouserd);
+ return -EINVAL;
+ }
+
+ chid = div_u64(ouserd, chan->func->userd->size);
+
+ list_for_each_entry(userd, &fifo->userd.list, head) {
+ if (userd->mem == muserd) {
+ if (userd->used & BIT(chid))
+ return -EBUSY;
+ break;
+ }
+ }
+
+ if (&userd->head == &fifo->userd.list) {
+ if (nvkm_memory_size(muserd) < userd_size) {
+ RUNL_DEBUG(runl, "userd too small");
+ return -EINVAL;
+ }
+
+ userd = kzalloc(sizeof(*userd), GFP_KERNEL);
+ if (!userd)
+ return -ENOMEM;
+
+ userd->chid = nvkm_chid_get(runl->chid, chan);
+ if (userd->chid < 0) {
+ ret = userd->chid;
+ kfree(userd);
+ return ret;
+ }
+
+ userd->mem = nvkm_memory_ref(muserd);
+
+ ret = nvkm_memory_kmap(userd->mem, &userd->map);
+ if (ret) {
+ nvkm_chid_put(runl->chid, userd->chid, &chan->cgrp->lock);
+ kfree(userd);
+ return ret;
+ }
+
+
+ list_add(&userd->head, &fifo->userd.list);
+ }
+
+ userd->used |= BIT(chid);
+
+ chan->userd.mem = nvkm_memory_ref(userd->map);
+ chan->userd.base = ouserd;
+
+ return (userd->chid * CHID_PER_USERD) + chid;
+}
+
+static int
+r535_chan_id_get(struct nvkm_chan *chan, struct nvkm_memory *muserd, u64 ouserd)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ int ret;
+
+ mutex_lock(&fifo->userd.mutex);
+ ret = r535_chan_id_get_locked(chan, muserd, ouserd);
+ mutex_unlock(&fifo->userd.mutex);
+ return ret;
+}
+
+static const struct nvkm_chan_func
+r535_chan = {
+ .id_get = r535_chan_id_get,
+ .id_put = r535_chan_id_put,
+ .inst = &gf100_chan_inst,
+ .userd = &gv100_chan_userd,
+ .ramfc = &r535_chan_ramfc,
+ .start = r535_chan_start,
+ .stop = r535_chan_stop,
+ .doorbell_handle = r535_chan_doorbell_handle,
+};
+
+static const struct nvkm_cgrp_func
+r535_cgrp = {
+};
+
+static int
+r535_engn_nonstall(struct nvkm_engn *engn)
+{
+ struct nvkm_subdev *subdev = &engn->engine->subdev;
+ int ret;
+
+ ret = nvkm_gsp_intr_nonstall(subdev->device->gsp, subdev->type, subdev->inst);
+ WARN_ON(ret == -ENOENT);
+ return ret;
+}
+
+static const struct nvkm_engn_func
+r535_ce = {
+ .nonstall = r535_engn_nonstall,
+};
+
+static int
+r535_gr_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx, struct nvkm_chan *chan)
+{
+ /* RM requires GR context buffers to remain mapped until after the
+ * channel has been destroyed (as opposed to after the last gr obj
+ * has been deleted).
+ *
+ * Take an extra ref here, which will be released once the channel
+ * object has been deleted.
+ */
+ refcount_inc(&vctx->refs);
+ chan->rm.grctx = vctx;
+ return 0;
+}
+
+static const struct nvkm_engn_func
+r535_gr = {
+ .nonstall = r535_engn_nonstall,
+ .ctor2 = r535_gr_ctor,
+};
+
+static int
+r535_flcn_bind(struct nvkm_engn *engn, struct nvkm_vctx *vctx, struct nvkm_chan *chan)
+{
+ struct nvkm_gsp_client *client = &chan->vmm->rm.client;
+ NV2080_CTRL_GPU_PROMOTE_CTX_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&chan->vmm->rm.device.subdevice,
+ NV2080_CTRL_CMD_GPU_PROMOTE_CTX, sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->hClient = client->object.handle;
+ ctrl->hObject = chan->rm.object.handle;
+ ctrl->hChanClient = client->object.handle;
+ ctrl->virtAddress = vctx->vma->addr;
+ ctrl->size = vctx->inst->size;
+ ctrl->engineType = engn->id;
+ ctrl->ChID = chan->id;
+
+ return nvkm_gsp_rm_ctrl_wr(&chan->vmm->rm.device.subdevice, ctrl);
+}
+
+static int
+r535_flcn_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx, struct nvkm_chan *chan)
+{
+ int ret;
+
+ if (WARN_ON(!engn->rm.size))
+ return -EINVAL;
+
+ ret = nvkm_gpuobj_new(engn->engine->subdev.device, engn->rm.size, 0, true, NULL,
+ &vctx->inst);
+ if (ret)
+ return ret;
+
+ ret = nvkm_vmm_get(vctx->vmm, 12, vctx->inst->size, &vctx->vma);
+ if (ret)
+ return ret;
+
+ ret = nvkm_memory_map(vctx->inst, 0, vctx->vmm, vctx->vma, NULL, 0);
+ if (ret)
+ return ret;
+
+ return r535_flcn_bind(engn, vctx, chan);
+}
+
+static const struct nvkm_engn_func
+r535_flcn = {
+ .nonstall = r535_engn_nonstall,
+ .ctor2 = r535_flcn_ctor,
+};
+
+static void
+r535_runl_allow(struct nvkm_runl *runl, u32 engm)
+{
+}
+
+static void
+r535_runl_block(struct nvkm_runl *runl, u32 engm)
+{
+}
+
+static const struct nvkm_runl_func
+r535_runl = {
+ .block = r535_runl_block,
+ .allow = r535_runl_allow,
+};
+
+static int
+r535_fifo_2080_type(enum nvkm_subdev_type type, int inst)
+{
+ switch (type) {
+ case NVKM_ENGINE_GR: return NV2080_ENGINE_TYPE_GR0;
+ case NVKM_ENGINE_CE: return NV2080_ENGINE_TYPE_COPY0 + inst;
+ case NVKM_ENGINE_SEC2: return NV2080_ENGINE_TYPE_SEC2;
+ case NVKM_ENGINE_NVDEC: return NV2080_ENGINE_TYPE_NVDEC0 + inst;
+ case NVKM_ENGINE_NVENC: return NV2080_ENGINE_TYPE_NVENC0 + inst;
+ case NVKM_ENGINE_NVJPG: return NV2080_ENGINE_TYPE_NVJPEG0 + inst;
+ case NVKM_ENGINE_OFA: return NV2080_ENGINE_TYPE_OFA;
+ case NVKM_ENGINE_SW: return NV2080_ENGINE_TYPE_SW;
+ default:
+ break;
+ }
+
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static int
+r535_fifo_engn_type(RM_ENGINE_TYPE rm, enum nvkm_subdev_type *ptype)
+{
+ switch (rm) {
+ case RM_ENGINE_TYPE_GR0:
+ *ptype = NVKM_ENGINE_GR;
+ return 0;
+ case RM_ENGINE_TYPE_COPY0...RM_ENGINE_TYPE_COPY9:
+ *ptype = NVKM_ENGINE_CE;
+ return rm - RM_ENGINE_TYPE_COPY0;
+ case RM_ENGINE_TYPE_NVDEC0...RM_ENGINE_TYPE_NVDEC7:
+ *ptype = NVKM_ENGINE_NVDEC;
+ return rm - RM_ENGINE_TYPE_NVDEC0;
+ case RM_ENGINE_TYPE_NVENC0...RM_ENGINE_TYPE_NVENC2:
+ *ptype = NVKM_ENGINE_NVENC;
+ return rm - RM_ENGINE_TYPE_NVENC0;
+ case RM_ENGINE_TYPE_SW:
+ *ptype = NVKM_ENGINE_SW;
+ return 0;
+ case RM_ENGINE_TYPE_SEC2:
+ *ptype = NVKM_ENGINE_SEC2;
+ return 0;
+ case RM_ENGINE_TYPE_NVJPEG0...RM_ENGINE_TYPE_NVJPEG7:
+ *ptype = NVKM_ENGINE_NVJPG;
+ return rm - RM_ENGINE_TYPE_NVJPEG0;
+ case RM_ENGINE_TYPE_OFA:
+ *ptype = NVKM_ENGINE_OFA;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+r535_fifo_ectx_size(struct nvkm_fifo *fifo)
+{
+ NV2080_CTRL_INTERNAL_GET_CONSTRUCTED_FALCON_INFO_PARAMS *ctrl;
+ struct nvkm_gsp *gsp = fifo->engine.subdev.device->gsp;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_INTERNAL_GET_CONSTRUCTED_FALCON_INFO,
+ sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return PTR_ERR(ctrl);
+
+ for (int i = 0; i < ctrl->numConstructedFalcons; i++) {
+ nvkm_runl_foreach(runl, fifo) {
+ nvkm_runl_foreach_engn(engn, runl) {
+ if (engn->rm.desc == ctrl->constructedFalconsTable[i].engDesc) {
+ engn->rm.size =
+ ctrl->constructedFalconsTable[i].ctxBufferSize;
+ break;
+ }
+ }
+ }
+ }
+
+ nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);
+ return 0;
+}
+
+static int
+r535_fifo_runl_ctor(struct nvkm_fifo *fifo)
+{
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ struct nvkm_gsp *gsp = subdev->device->gsp;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ u32 cgids = 2048;
+ u32 chids = 2048;
+ int ret;
+ NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_PARAMS *ctrl;
+
+ if ((ret = nvkm_chid_new(&nvkm_chan_event, subdev, cgids, 0, cgids, &fifo->cgid)) ||
+ (ret = nvkm_chid_new(&nvkm_chan_event, subdev, chids, 0, chids, &fifo->chid)))
+ return ret;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_FIFO_GET_DEVICE_INFO_TABLE, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return PTR_ERR(ctrl);
+
+ for (int i = 0; i < ctrl->numEntries; i++) {
+ const u32 addr = ctrl->entries[i].engineData[ENGINE_INFO_TYPE_RUNLIST_PRI_BASE];
+ const u32 id = ctrl->entries[i].engineData[ENGINE_INFO_TYPE_RUNLIST];
+
+ runl = nvkm_runl_get(fifo, id, addr);
+ if (!runl) {
+ runl = nvkm_runl_new(fifo, id, addr, 0);
+ if (WARN_ON(IS_ERR(runl)))
+ continue;
+ }
+ }
+
+ for (int i = 0; i < ctrl->numEntries; i++) {
+ const u32 addr = ctrl->entries[i].engineData[ENGINE_INFO_TYPE_RUNLIST_PRI_BASE];
+ const u32 rmid = ctrl->entries[i].engineData[ENGINE_INFO_TYPE_RM_ENGINE_TYPE];
+ const u32 id = ctrl->entries[i].engineData[ENGINE_INFO_TYPE_RUNLIST];
+ enum nvkm_subdev_type type;
+ int inst, nv2080;
+
+ runl = nvkm_runl_get(fifo, id, addr);
+ if (!runl)
+ continue;
+
+ inst = r535_fifo_engn_type(rmid, &type);
+ if (inst < 0) {
+ nvkm_warn(subdev, "RM_ENGINE_TYPE 0x%x\n", rmid);
+ nvkm_runl_del(runl);
+ continue;
+ }
+
+ nv2080 = r535_fifo_2080_type(type, inst);
+ if (nv2080 < 0) {
+ nvkm_runl_del(runl);
+ continue;
+ }
+
+ switch (type) {
+ case NVKM_ENGINE_CE:
+ engn = nvkm_runl_add(runl, nv2080, &r535_ce, type, inst);
+ break;
+ case NVKM_ENGINE_GR:
+ engn = nvkm_runl_add(runl, nv2080, &r535_gr, type, inst);
+ break;
+ case NVKM_ENGINE_NVDEC:
+ case NVKM_ENGINE_NVENC:
+ case NVKM_ENGINE_NVJPG:
+ case NVKM_ENGINE_OFA:
+ engn = nvkm_runl_add(runl, nv2080, &r535_flcn, type, inst);
+ break;
+ case NVKM_ENGINE_SW:
+ continue;
+ default:
+ engn = NULL;
+ break;
+ }
+
+ if (!engn) {
+ nvkm_runl_del(runl);
+ continue;
+ }
+
+ engn->rm.desc = ctrl->entries[i].engineData[ENGINE_INFO_TYPE_ENG_DESC];
+ }
+
+ nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);
+
+ {
+ NV2080_CTRL_CE_GET_FAULT_METHOD_BUFFER_SIZE_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_CE_GET_FAULT_METHOD_BUFFER_SIZE,
+ sizeof(*ctrl));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ fifo->rm.mthdbuf_size = ctrl->size;
+
+ nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);
+ }
+
+ return r535_fifo_ectx_size(fifo);
+}
+
+static void
+r535_fifo_dtor(struct nvkm_fifo *fifo)
+{
+ kfree(fifo->func);
+}
+
+int
+r535_fifo_new(const struct nvkm_fifo_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo)
+{
+ struct nvkm_fifo_func *rm;
+
+ if (!(rm = kzalloc(sizeof(*rm), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_fifo_dtor;
+ rm->runl_ctor = r535_fifo_runl_ctor;
+ rm->runl = &r535_runl;
+ rm->cgrp = hw->cgrp;
+ rm->cgrp.func = &r535_cgrp;
+ rm->chan = hw->chan;
+ rm->chan.func = &r535_chan;
+ rm->nonstall = &ga100_fifo_nonstall;
+ rm->nonstall_ctor = ga100_fifo_nonstall_ctor;
+
+ return nvkm_fifo_new_(rm, device, type, inst, pfifo);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h
index 5421321f8e..19e6772ead 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h
@@ -18,6 +18,7 @@ struct nvkm_engn {
bool (*mmu_fault_triggered)(struct nvkm_engn *);
int (*ctor)(struct nvkm_engn *, struct nvkm_vctx *);
void (*bind)(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *);
+ int (*ctor2)(struct nvkm_engn *, struct nvkm_vctx *, struct nvkm_chan *);
int (*ramht_add)(struct nvkm_engn *, struct nvkm_object *, struct nvkm_chan *);
void (*ramht_del)(struct nvkm_chan *, int hash);
} *func;
@@ -28,6 +29,11 @@ struct nvkm_engn {
int fault;
+ struct {
+ u32 desc;
+ u32 size;
+ } rm;
+
struct list_head head;
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
index ea9e151dbb..1d39a6840a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
@@ -25,6 +25,7 @@
#include "runl.h"
#include <core/memory.h>
+#include <subdev/gsp.h>
#include <subdev/mc.h>
#include <subdev/vfn.h>
@@ -282,5 +283,8 @@ int
tu102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_fifo_new(&tu102_fifo, device, type, inst, pfifo);
+
return nvkm_fifo_new_(&tu102_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c
index 04140e0110..9e56bcc166 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c
@@ -317,6 +317,15 @@ nvkm_uchan = {
.uevent = nvkm_uchan_uevent,
};
+struct nvkm_chan *
+nvkm_uchan_chan(struct nvkm_object *object)
+{
+ if (WARN_ON(object->func != &nvkm_uchan))
+ return NULL;
+
+ return nvkm_uchan(object)->chan;
+}
+
int
nvkm_uchan_new(struct nvkm_fifo *fifo, struct nvkm_cgrp *cgrp, const struct nvkm_oclass *oclass,
void *argv, u32 argc, struct nvkm_object **pobject)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
index b5418f05cc..1555f8c40b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
@@ -41,6 +41,9 @@ nvkm-y += nvkm/engine/gr/gp10b.o
nvkm-y += nvkm/engine/gr/gv100.o
nvkm-y += nvkm/engine/gr/tu102.o
nvkm-y += nvkm/engine/gr/ga102.o
+nvkm-y += nvkm/engine/gr/ad102.o
+
+nvkm-y += nvkm/engine/gr/r535.o
nvkm-y += nvkm/engine/gr/ctxnv40.o
nvkm-y += nvkm/engine/gr/ctxnv50.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ad102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ad102.c
new file mode 100644
index 0000000000..7bfa6240d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ad102.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 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 "gf100.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct gf100_gr_func
+ad102_gr = {
+ .sclass = {
+ { -1, -1, FERMI_TWOD_A },
+ { -1, -1, KEPLER_INLINE_TO_MEMORY_B },
+ { -1, -1, ADA_A },
+ { -1, -1, ADA_COMPUTE_A },
+ {}
+ }
+};
+
+int
+ad102_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_gr_new(&ad102_gr, device, type, inst, pgr);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
index 0096ad401b..f5e68f09df 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
@@ -160,7 +160,11 @@ static int
nvkm_gr_init(struct nvkm_engine *engine)
{
struct nvkm_gr *gr = nvkm_gr(engine);
- return gr->func->init(gr);
+
+ if (gr->func->init)
+ return gr->func->init(gr);
+
+ return 0;
}
static int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c
index 00cd70abad..d285c597af 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c
@@ -23,6 +23,7 @@
#include "ctxgf100.h"
#include <core/firmware.h>
+#include <subdev/gsp.h>
#include <subdev/acr.h>
#include <subdev/timer.h>
#include <subdev/vfn.h>
@@ -350,5 +351,8 @@ ga102_gr_fwif[] = {
int
ga102_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_gr_new(&ga102_gr, device, type, inst, pgr);
+
return gf100_gr_new_(ga102_gr_fwif, device, type, inst, pgr);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
index 3648868bb9..c494a1ff2d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -2032,18 +2032,18 @@ gf100_gr_oneinit(struct nvkm_gr *base)
}
/* Allocate global context buffers. */
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->pagepool_size,
- 0x100, false, &gr->pagepool);
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST_SR_LOST,
+ gr->func->grctx->pagepool_size, 0x100, false, &gr->pagepool);
if (ret)
return ret;
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->bundle_size,
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST_SR_LOST, gr->func->grctx->bundle_size,
0x100, false, &gr->bundle_cb);
if (ret)
return ret;
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->attrib_cb_size(gr),
- 0x1000, false, &gr->attrib_cb);
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST_SR_LOST,
+ gr->func->grctx->attrib_cb_size(gr), 0x1000, false, &gr->attrib_cb);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
index 54f686ba39..b0e0c93050 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -445,4 +445,6 @@ void gp108_gr_acr_bld_patch(struct nvkm_acr *, u32, s64);
int gf100_gr_new_(const struct gf100_gr_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_gr **);
+int r535_gr_new(const struct gf100_gr_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
+ struct nvkm_gr **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/r535.c
new file mode 100644
index 0000000000..f4bed3eb1e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/r535.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2023 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 "gf100.h"
+
+#include <core/memory.h>
+#include <subdev/gsp.h>
+#include <subdev/mmu/vmm.h>
+#include <engine/fifo/priv.h>
+
+#include <nvif/if900d.h>
+
+#include <nvhw/drf.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/alloc/alloc_channel.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0080/ctrl0080fifo.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080gpu.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080internal.h>
+#include <nvrm/535.113.01/nvidia/generated/g_kernel_channel_nvoc.h>
+
+#define r535_gr(p) container_of((p), struct r535_gr, base)
+
+#define R515_GR_MAX_CTXBUFS 9
+
+struct r535_gr {
+ struct nvkm_gr base;
+
+ struct {
+ u16 bufferId;
+ u32 size;
+ u8 page;
+ u8 align;
+ bool global;
+ bool init;
+ bool ro;
+ } ctxbuf[R515_GR_MAX_CTXBUFS];
+ int ctxbuf_nr;
+
+ struct nvkm_memory *ctxbuf_mem[R515_GR_MAX_CTXBUFS];
+};
+
+struct r535_gr_chan {
+ struct nvkm_object object;
+ struct r535_gr *gr;
+
+ struct nvkm_vmm *vmm;
+ struct nvkm_chan *chan;
+
+ struct nvkm_memory *mem[R515_GR_MAX_CTXBUFS];
+ struct nvkm_vma *vma[R515_GR_MAX_CTXBUFS];
+};
+
+struct r535_gr_obj {
+ struct nvkm_object object;
+ struct nvkm_gsp_object rm;
+};
+
+static void *
+r535_gr_obj_dtor(struct nvkm_object *object)
+{
+ struct r535_gr_obj *obj = container_of(object, typeof(*obj), object);
+
+ nvkm_gsp_rm_free(&obj->rm);
+ return obj;
+}
+
+static const struct nvkm_object_func
+r535_gr_obj = {
+ .dtor = r535_gr_obj_dtor,
+};
+
+static int
+r535_gr_obj_ctor(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct r535_gr_chan *chan = container_of(oclass->parent, typeof(*chan), object);
+ struct r535_gr_obj *obj;
+
+ if (!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_gr_obj, oclass, &obj->object);
+ *pobject = &obj->object;
+
+ return nvkm_gsp_rm_alloc(&chan->chan->rm.object, oclass->handle, oclass->base.oclass, 0,
+ &obj->rm);
+}
+
+static void *
+r535_gr_chan_dtor(struct nvkm_object *object)
+{
+ struct r535_gr_chan *grc = container_of(object, typeof(*grc), object);
+ struct r535_gr *gr = grc->gr;
+
+ for (int i = 0; i < gr->ctxbuf_nr; i++) {
+ nvkm_vmm_put(grc->vmm, &grc->vma[i]);
+ nvkm_memory_unref(&grc->mem[i]);
+ }
+
+ nvkm_vmm_unref(&grc->vmm);
+ return grc;
+}
+
+static const struct nvkm_object_func
+r535_gr_chan = {
+ .dtor = r535_gr_chan_dtor,
+};
+
+static int
+r535_gr_promote_ctx(struct r535_gr *gr, bool golden, struct nvkm_vmm *vmm,
+ struct nvkm_memory **pmem, struct nvkm_vma **pvma,
+ struct nvkm_gsp_object *chan)
+{
+ struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ NV2080_CTRL_GPU_PROMOTE_CTX_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&vmm->rm.device.subdevice,
+ NV2080_CTRL_CMD_GPU_PROMOTE_CTX, sizeof(*ctrl));
+ if (WARN_ON(IS_ERR(ctrl)))
+ return PTR_ERR(ctrl);
+
+ ctrl->engineType = 1;
+ ctrl->hChanClient = vmm->rm.client.object.handle;
+ ctrl->hObject = chan->handle;
+
+ for (int i = 0; i < gr->ctxbuf_nr; i++) {
+ NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ENTRY *entry =
+ &ctrl->promoteEntry[ctrl->entryCount];
+ const bool alloc = golden || !gr->ctxbuf[i].global;
+ int ret;
+
+ entry->bufferId = gr->ctxbuf[i].bufferId;
+ entry->bInitialize = gr->ctxbuf[i].init && alloc;
+
+ if (alloc) {
+ ret = nvkm_memory_new(device, gr->ctxbuf[i].init ?
+ NVKM_MEM_TARGET_INST : NVKM_MEM_TARGET_INST_SR_LOST,
+ gr->ctxbuf[i].size, 1 << gr->ctxbuf[i].page,
+ gr->ctxbuf[i].init, &pmem[i]);
+ if (WARN_ON(ret))
+ return ret;
+
+ if (gr->ctxbuf[i].bufferId ==
+ NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PRIV_ACCESS_MAP)
+ entry->bNonmapped = 1;
+ } else {
+ if (gr->ctxbuf[i].bufferId ==
+ NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_UNRESTRICTED_PRIV_ACCESS_MAP)
+ continue;
+
+ pmem[i] = nvkm_memory_ref(gr->ctxbuf_mem[i]);
+ }
+
+ if (!entry->bNonmapped) {
+ struct gf100_vmm_map_v0 args = {
+ .priv = 1,
+ .ro = gr->ctxbuf[i].ro,
+ };
+
+ mutex_lock(&vmm->mutex.vmm);
+ ret = nvkm_vmm_get_locked(vmm, false, true, false, 0, gr->ctxbuf[i].align,
+ nvkm_memory_size(pmem[i]), &pvma[i]);
+ mutex_unlock(&vmm->mutex.vmm);
+ if (ret)
+ return ret;
+
+ ret = nvkm_memory_map(pmem[i], 0, vmm, pvma[i], &args, sizeof(args));
+ if (ret)
+ return ret;
+
+ entry->gpuVirtAddr = pvma[i]->addr;
+ }
+
+ if (entry->bInitialize) {
+ entry->gpuPhysAddr = nvkm_memory_addr(pmem[i]);
+ entry->size = gr->ctxbuf[i].size;
+ entry->physAttr = 4;
+ }
+
+ nvkm_debug(subdev,
+ "promote %02d: pa %016llx/%08x sz %016llx va %016llx init:%d nm:%d\n",
+ entry->bufferId, entry->gpuPhysAddr, entry->physAttr, entry->size,
+ entry->gpuVirtAddr, entry->bInitialize, entry->bNonmapped);
+
+ ctrl->entryCount++;
+ }
+
+ return nvkm_gsp_rm_ctrl_wr(&vmm->rm.device.subdevice, ctrl);
+}
+
+static int
+r535_gr_chan_new(struct nvkm_gr *base, struct nvkm_chan *chan, const struct nvkm_oclass *oclass,
+ struct nvkm_object **pobject)
+{
+ struct r535_gr *gr = r535_gr(base);
+ struct r535_gr_chan *grc;
+ int ret;
+
+ if (!(grc = kzalloc(sizeof(*grc), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_gr_chan, oclass, &grc->object);
+ grc->gr = gr;
+ grc->vmm = nvkm_vmm_ref(chan->vmm);
+ grc->chan = chan;
+ *pobject = &grc->object;
+
+ ret = r535_gr_promote_ctx(gr, false, grc->vmm, grc->mem, grc->vma, &chan->rm.object);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static u64
+r535_gr_units(struct nvkm_gr *gr)
+{
+ struct nvkm_gsp *gsp = gr->engine.subdev.device->gsp;
+
+ return (gsp->gr.tpcs << 8) | gsp->gr.gpcs;
+}
+
+static int
+r535_gr_oneinit(struct nvkm_gr *base)
+{
+ NV2080_CTRL_INTERNAL_STATIC_GR_GET_CONTEXT_BUFFERS_INFO_PARAMS *info;
+ struct r535_gr *gr = container_of(base, typeof(*gr), base);
+ struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ struct nvkm_gsp *gsp = device->gsp;
+ struct nvkm_mmu *mmu = device->mmu;
+ struct {
+ struct nvkm_memory *inst;
+ struct nvkm_vmm *vmm;
+ struct nvkm_gsp_object chan;
+ struct nvkm_vma *vma[R515_GR_MAX_CTXBUFS];
+ } golden = {};
+ int ret;
+
+ /* Allocate a channel to use for golden context init. */
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x12000, 0, true, &golden.inst);
+ if (ret)
+ goto done;
+
+ ret = nvkm_vmm_new(device, 0x1000, 0, NULL, 0, NULL, "grGoldenVmm", &golden.vmm);
+ if (ret)
+ goto done;
+
+ ret = mmu->func->promote_vmm(golden.vmm);
+ if (ret)
+ goto done;
+
+ {
+ NV_CHANNELGPFIFO_ALLOCATION_PARAMETERS *args;
+
+ args = nvkm_gsp_rm_alloc_get(&golden.vmm->rm.device.object, 0xf1f00000,
+ device->fifo->func->chan.user.oclass,
+ sizeof(*args), &golden.chan);
+ if (IS_ERR(args)) {
+ ret = PTR_ERR(args);
+ goto done;
+ }
+
+ args->gpFifoOffset = 0;
+ args->gpFifoEntries = 0x1000 / 8;
+ args->flags =
+ NVDEF(NVOS04, FLAGS, CHANNEL_TYPE, PHYSICAL) |
+ NVDEF(NVOS04, FLAGS, VPR, FALSE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_SKIP_MAP_REFCOUNTING, FALSE) |
+ NVVAL(NVOS04, FLAGS, GROUP_CHANNEL_RUNQUEUE, 0) |
+ NVDEF(NVOS04, FLAGS, PRIVILEGED_CHANNEL, TRUE) |
+ NVDEF(NVOS04, FLAGS, DELAY_CHANNEL_SCHEDULING, FALSE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_DENY_PHYSICAL_MODE_CE, FALSE) |
+ NVVAL(NVOS04, FLAGS, CHANNEL_USERD_INDEX_VALUE, 0) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_USERD_INDEX_FIXED, FALSE) |
+ NVVAL(NVOS04, FLAGS, CHANNEL_USERD_INDEX_PAGE_VALUE, 0) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_USERD_INDEX_PAGE_FIXED, TRUE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_DENY_AUTH_LEVEL_PRIV, FALSE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_SKIP_SCRUBBER, FALSE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_CLIENT_MAP_FIFO, FALSE) |
+ NVDEF(NVOS04, FLAGS, SET_EVICT_LAST_CE_PREFETCH_CHANNEL, FALSE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_VGPU_PLUGIN_CONTEXT, FALSE) |
+ NVDEF(NVOS04, FLAGS, CHANNEL_PBDMA_ACQUIRE_TIMEOUT, FALSE) |
+ NVDEF(NVOS04, FLAGS, GROUP_CHANNEL_THREAD, DEFAULT) |
+ NVDEF(NVOS04, FLAGS, MAP_CHANNEL, FALSE) |
+ NVDEF(NVOS04, FLAGS, SKIP_CTXBUFFER_ALLOC, FALSE);
+ args->hVASpace = golden.vmm->rm.object.handle;
+ args->engineType = 1;
+ args->instanceMem.base = nvkm_memory_addr(golden.inst);
+ args->instanceMem.size = 0x1000;
+ args->instanceMem.addressSpace = 2;
+ args->instanceMem.cacheAttrib = 1;
+ args->ramfcMem.base = nvkm_memory_addr(golden.inst);
+ args->ramfcMem.size = 0x200;
+ args->ramfcMem.addressSpace = 2;
+ args->ramfcMem.cacheAttrib = 1;
+ args->userdMem.base = nvkm_memory_addr(golden.inst) + 0x1000;
+ args->userdMem.size = 0x200;
+ args->userdMem.addressSpace = 2;
+ args->userdMem.cacheAttrib = 1;
+ args->mthdbufMem.base = nvkm_memory_addr(golden.inst) + 0x2000;
+ args->mthdbufMem.size = 0x5000;
+ args->mthdbufMem.addressSpace = 2;
+ args->mthdbufMem.cacheAttrib = 1;
+ args->internalFlags =
+ NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, PRIVILEGE, ADMIN) |
+ NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, ERROR_NOTIFIER_TYPE, NONE) |
+ NVDEF(NV_KERNELCHANNEL, ALLOC_INTERNALFLAGS, ECC_ERROR_NOTIFIER_TYPE, NONE);
+
+ ret = nvkm_gsp_rm_alloc_wr(&golden.chan, args);
+ if (ret)
+ goto done;
+ }
+
+ /* Fetch context buffer info from RM and allocate each of them here to use
+ * during golden context init (or later as a global context buffer).
+ *
+ * Also build the information that'll be used to create channel contexts.
+ */
+ info = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
+ NV2080_CTRL_CMD_INTERNAL_STATIC_KGR_GET_CONTEXT_BUFFERS_INFO,
+ sizeof(*info));
+ if (WARN_ON(IS_ERR(info))) {
+ ret = PTR_ERR(info);
+ goto done;
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(info->engineContextBuffersInfo[0].engine); i++) {
+ static const struct {
+ u32 id0; /* NV0080_CTRL_FIFO_GET_ENGINE_CONTEXT_PROPERTIES_ENGINE_ID */
+ u32 id1; /* NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID */
+ bool global;
+ bool init;
+ bool ro;
+ } map[] = {
+#define _A(n,N,G,I,R) { .id0 = NV0080_CTRL_FIFO_GET_ENGINE_CONTEXT_PROPERTIES_ENGINE_ID_##n, \
+ .id1 = NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_##N, \
+ .global = (G), .init = (I), .ro = (R) }
+#define _B(N,G,I,R) _A(GRAPHICS_##N, N, (G), (I), (R))
+ /* global init ro */
+ _A( GRAPHICS, MAIN, false, true, false),
+ _B( PATCH, false, true, false),
+ _A( GRAPHICS_BUNDLE_CB, BUFFER_BUNDLE_CB, true, false, false),
+ _B( PAGEPOOL, true, false, false),
+ _B( ATTRIBUTE_CB, true, false, false),
+ _B( RTV_CB_GLOBAL, true, false, false),
+ _B( FECS_EVENT, true, true, false),
+ _B( PRIV_ACCESS_MAP, true, true, true),
+#undef _B
+#undef _A
+ };
+ u32 size = info->engineContextBuffersInfo[0].engine[i].size;
+ u8 align, page;
+ int id;
+
+ for (id = 0; id < ARRAY_SIZE(map); id++) {
+ if (map[id].id0 == i)
+ break;
+ }
+
+ nvkm_debug(subdev, "%02x: size:0x%08x %s\n", i,
+ size, (id < ARRAY_SIZE(map)) ? "*" : "");
+ if (id >= ARRAY_SIZE(map))
+ continue;
+
+ if (map[id].id1 == NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_MAIN)
+ size = ALIGN(size, 0x1000) + 64 * 0x1000; /* per-subctx headers */
+
+ if (size >= 1 << 21) page = 21;
+ else if (size >= 1 << 16) page = 16;
+ else page = 12;
+
+ if (map[id].id1 == NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_ATTRIBUTE_CB)
+ align = order_base_2(size);
+ else
+ align = page;
+
+ if (WARN_ON(gr->ctxbuf_nr == ARRAY_SIZE(gr->ctxbuf)))
+ continue;
+
+ gr->ctxbuf[gr->ctxbuf_nr].bufferId = map[id].id1;
+ gr->ctxbuf[gr->ctxbuf_nr].size = size;
+ gr->ctxbuf[gr->ctxbuf_nr].page = page;
+ gr->ctxbuf[gr->ctxbuf_nr].align = align;
+ gr->ctxbuf[gr->ctxbuf_nr].global = map[id].global;
+ gr->ctxbuf[gr->ctxbuf_nr].init = map[id].init;
+ gr->ctxbuf[gr->ctxbuf_nr].ro = map[id].ro;
+ gr->ctxbuf_nr++;
+
+ if (map[id].id1 == NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_PRIV_ACCESS_MAP) {
+ if (WARN_ON(gr->ctxbuf_nr == ARRAY_SIZE(gr->ctxbuf)))
+ continue;
+
+ gr->ctxbuf[gr->ctxbuf_nr] = gr->ctxbuf[gr->ctxbuf_nr - 1];
+ gr->ctxbuf[gr->ctxbuf_nr].bufferId =
+ NV2080_CTRL_GPU_PROMOTE_CTX_BUFFER_ID_UNRESTRICTED_PRIV_ACCESS_MAP;
+ gr->ctxbuf_nr++;
+ }
+ }
+
+ nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, info);
+
+ /* Promote golden context to RM. */
+ ret = r535_gr_promote_ctx(gr, true, golden.vmm, gr->ctxbuf_mem, golden.vma, &golden.chan);
+ if (ret)
+ goto done;
+
+ /* Allocate 3D class on channel to trigger golden context init in RM. */
+ {
+ int i;
+
+ for (i = 0; gr->base.func->sclass[i].ctor; i++) {
+ if ((gr->base.func->sclass[i].oclass & 0xff) == 0x97) {
+ struct nvkm_gsp_object threed;
+
+ ret = nvkm_gsp_rm_alloc(&golden.chan, 0x97000000,
+ gr->base.func->sclass[i].oclass, 0,
+ &threed);
+ if (ret)
+ goto done;
+
+ nvkm_gsp_rm_free(&threed);
+ break;
+ }
+ }
+
+ if (WARN_ON(!gr->base.func->sclass[i].ctor)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ nvkm_gsp_rm_free(&golden.chan);
+ for (int i = gr->ctxbuf_nr - 1; i >= 0; i--)
+ nvkm_vmm_put(golden.vmm, &golden.vma[i]);
+ nvkm_vmm_unref(&golden.vmm);
+ nvkm_memory_unref(&golden.inst);
+ return ret;
+
+}
+
+static void *
+r535_gr_dtor(struct nvkm_gr *base)
+{
+ struct r535_gr *gr = r535_gr(base);
+
+ while (gr->ctxbuf_nr)
+ nvkm_memory_unref(&gr->ctxbuf_mem[--gr->ctxbuf_nr]);
+
+ kfree(gr->base.func);
+ return gr;
+}
+
+int
+r535_gr_new(const struct gf100_gr_func *hw,
+ struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
+{
+ struct nvkm_gr_func *rm;
+ struct r535_gr *gr;
+ int nclass;
+
+ for (nclass = 0; hw->sclass[nclass].oclass; nclass++);
+
+ if (!(rm = kzalloc(sizeof(*rm) + (nclass + 1) * sizeof(rm->sclass[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_gr_dtor;
+ rm->oneinit = r535_gr_oneinit;
+ rm->units = r535_gr_units;
+ rm->chan_new = r535_gr_chan_new;
+
+ for (int i = 0; i < nclass; i++) {
+ rm->sclass[i].minver = hw->sclass[i].minver;
+ rm->sclass[i].maxver = hw->sclass[i].maxver;
+ rm->sclass[i].oclass = hw->sclass[i].oclass;
+ rm->sclass[i].ctor = r535_gr_obj_ctor;
+ }
+
+ if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) {
+ kfree(rm);
+ return -ENOMEM;
+ }
+
+ *pgr = &gr->base;
+
+ return nvkm_gr_ctor(rm, device, type, inst, true, &gr->base);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
index a7775aa185..b7a458e904 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
@@ -22,6 +22,8 @@
#include "gf100.h"
#include "ctxgf100.h"
+#include <subdev/gsp.h>
+
#include <nvif/class.h>
void
@@ -216,5 +218,8 @@ tu102_gr_fwif[] = {
int
tu102_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_gr_new(&tu102_gr, device, type, inst, pgr);
+
return gf100_gr_new_(tu102_gr_fwif, device, type, inst, pgr);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
index f05e79670d..2b0e923cb7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
@@ -1,4 +1,9 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/nvdec/base.o
nvkm-y += nvkm/engine/nvdec/gm107.o
+nvkm-y += nvkm/engine/nvdec/tu102.o
+nvkm-y += nvkm/engine/nvdec/ga100.o
nvkm-y += nvkm/engine/nvdec/ga102.o
+nvkm-y += nvkm/engine/nvdec/ad102.o
+
+nvkm-y += nvkm/engine/nvdec/r535.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ad102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ad102.c
new file mode 100644
index 0000000000..d72b3aae9a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ad102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ad102_nvdec = {
+ .sclass = {
+ { -1, -1, NVC9B0_VIDEO_DECODER },
+ {}
+ }
+};
+
+int
+ad102_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvdec **pnvdec)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvdec_new(&ad102_nvdec, device, type, inst, pnvdec);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
index 1f6e3b32ba..7d1c6791ae 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
@@ -33,6 +33,7 @@ nvkm_nvdec_dtor(struct nvkm_engine *engine)
static const struct nvkm_engine_func
nvkm_nvdec = {
.dtor = nvkm_nvdec_dtor,
+ .sclass = { {} },
};
int
@@ -58,4 +59,4 @@ nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device,
return nvkm_falcon_ctor(nvdec->func->flcn, &nvdec->engine.subdev,
nvdec->engine.subdev.name, addr, &nvdec->falcon);
-};
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga100.c
new file mode 100644
index 0000000000..932934227b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga100.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ga100_nvdec = {
+ .sclass = {
+ { -1, -1, NVC6B0_VIDEO_DECODER },
+ {}
+ }
+};
+
+int
+ga100_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvdec **pnvdec)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvdec_new(&ga100_nvdec, device, type, inst, pnvdec);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c
index 37d8c3c0f3..022a9c8243 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c
@@ -21,8 +21,17 @@
*/
#include "priv.h"
-#include <subdev/mc.h>
-#include <subdev/timer.h>
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ga102_nvdec_gsp = {
+ .sclass = {
+ { -1, -1, NVC7B0_VIDEO_DECODER },
+ {}
+ }
+};
static const struct nvkm_falcon_func
ga102_nvdec_flcn = {
@@ -57,5 +66,8 @@ int
ga102_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_nvdec **pnvdec)
{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvdec_new(&ga102_nvdec_gsp, device, type, inst, pnvdec);
+
return nvkm_nvdec_new_(ga102_nvdec_fwif, device, type, inst, 0x848000, pnvdec);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
index 564f7e8960..51c9d0e68e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
@@ -44,7 +44,7 @@ gm107_nvdec_nofw(struct nvkm_nvdec *nvdec, int ver,
return 0;
}
-static const struct nvkm_nvdec_fwif
+const struct nvkm_nvdec_fwif
gm107_nvdec_fwif[] = {
{ -1, gm107_nvdec_nofw, &gm107_nvdec },
{}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
index 61e1f7aaa5..f506ae83bf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
@@ -5,6 +5,8 @@
struct nvkm_nvdec_func {
const struct nvkm_falcon_func *flcn;
+
+ struct nvkm_sclass sclass[];
};
struct nvkm_nvdec_fwif {
@@ -14,6 +16,11 @@ struct nvkm_nvdec_fwif {
const struct nvkm_nvdec_func *func;
};
+extern const struct nvkm_nvdec_fwif gm107_nvdec_fwif[];
+
int nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *,
enum nvkm_subdev_type, int, u32 addr, struct nvkm_nvdec **);
+
+int r535_nvdec_new(const struct nvkm_engine_func *, struct nvkm_device *,
+ enum nvkm_subdev_type, int, struct nvkm_nvdec **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/r535.c
new file mode 100644
index 0000000000..75a24f3e66
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/r535.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <core/object.h>
+#include <subdev/gsp.h>
+#include <engine/fifo.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>
+
+struct r535_nvdec_obj {
+ struct nvkm_object object;
+ struct nvkm_gsp_object rm;
+};
+
+static void *
+r535_nvdec_obj_dtor(struct nvkm_object *object)
+{
+ struct r535_nvdec_obj *obj = container_of(object, typeof(*obj), object);
+
+ nvkm_gsp_rm_free(&obj->rm);
+ return obj;
+}
+
+static const struct nvkm_object_func
+r535_nvdec_obj = {
+ .dtor = r535_nvdec_obj_dtor,
+};
+
+static int
+r535_nvdec_obj_ctor(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_chan *chan = nvkm_uchan_chan(oclass->parent);
+ struct r535_nvdec_obj *obj;
+ NV_BSP_ALLOCATION_PARAMETERS *args;
+
+ if (!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_nvdec_obj, oclass, &obj->object);
+ *pobject = &obj->object;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->rm.object, oclass->handle, oclass->base.oclass,
+ sizeof(*args), &obj->rm);
+ if (WARN_ON(IS_ERR(args)))
+ return PTR_ERR(args);
+
+ args->size = sizeof(*args);
+ args->engineInstance = oclass->engine->subdev.inst;
+
+ return nvkm_gsp_rm_alloc_wr(&obj->rm, args);
+}
+
+static void *
+r535_nvdec_dtor(struct nvkm_engine *engine)
+{
+ struct nvkm_nvdec *nvdec = nvkm_nvdec(engine);
+
+ kfree(nvdec->engine.func);
+ return nvdec;
+}
+
+int
+r535_nvdec_new(const struct nvkm_engine_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_nvdec **pnvdec)
+{
+ struct nvkm_engine_func *rm;
+ int nclass;
+
+ for (nclass = 0; hw->sclass[nclass].oclass; nclass++);
+
+ if (!(rm = kzalloc(sizeof(*rm) + (nclass + 1) * sizeof(rm->sclass[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_nvdec_dtor;
+ for (int i = 0; i < nclass; i++) {
+ rm->sclass[i].minver = hw->sclass[i].minver;
+ rm->sclass[i].maxver = hw->sclass[i].maxver;
+ rm->sclass[i].oclass = hw->sclass[i].oclass;
+ rm->sclass[i].ctor = r535_nvdec_obj_ctor;
+ }
+
+ if (!(*pnvdec = kzalloc(sizeof(**pnvdec), GFP_KERNEL))) {
+ kfree(rm);
+ return -ENOMEM;
+ }
+
+ return nvkm_engine_ctor(rm, device, type, inst, true, &(*pnvdec)->engine);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/tu102.c
new file mode 100644
index 0000000000..808c8e010b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/tu102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+tu102_nvdec = {
+ .sclass = {
+ { -1, -1, NVC4B0_VIDEO_DECODER },
+ {}
+ }
+};
+
+int
+tu102_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvdec **pnvdec)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvdec_new(&tu102_nvdec, device, type, inst, pnvdec);
+
+ return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, 0, pnvdec);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/Kbuild
index 75bf4436bf..2c1495b730 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/Kbuild
@@ -1,3 +1,8 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/nvenc/base.o
nvkm-y += nvkm/engine/nvenc/gm107.o
+nvkm-y += nvkm/engine/nvenc/tu102.o
+nvkm-y += nvkm/engine/nvenc/ga102.o
+nvkm-y += nvkm/engine/nvenc/ad102.o
+
+nvkm-y += nvkm/engine/nvenc/r535.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ad102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ad102.c
new file mode 100644
index 0000000000..1b4619ff9e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ad102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ad102_nvenc = {
+ .sclass = {
+ { -1, -1, NVC9B7_VIDEO_ENCODER },
+ {}
+ }
+};
+
+int
+ad102_nvenc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvenc **pnvenc)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvenc_new(&ad102_nvenc, device, type, inst, pnvenc);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/base.c
index cf5dcfda7b..d45dbb42a0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/base.c
@@ -34,6 +34,7 @@ nvkm_nvenc_dtor(struct nvkm_engine *engine)
static const struct nvkm_engine_func
nvkm_nvenc = {
.dtor = nvkm_nvenc_dtor,
+ .sclass = { {} },
};
int
@@ -59,4 +60,4 @@ nvkm_nvenc_new_(const struct nvkm_nvenc_fwif *fwif, struct nvkm_device *device,
return nvkm_falcon_ctor(nvenc->func->flcn, &nvenc->engine.subdev,
nvenc->engine.subdev.name, 0, &nvenc->falcon);
-};
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ga102.c
new file mode 100644
index 0000000000..6463ab8e58
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/ga102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ga102_nvenc = {
+ .sclass = {
+ { -1, -1, NVC7B7_VIDEO_ENCODER },
+ {}
+ }
+};
+
+int
+ga102_nvenc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvenc **pnvenc)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvenc_new(&ga102_nvenc, device, type, inst, pnvenc);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c
index ad27d8b975..922abb647a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c
@@ -38,7 +38,7 @@ gm107_nvenc_nofw(struct nvkm_nvenc *nvenc, int ver,
return 0;
}
-static const struct nvkm_nvenc_fwif
+const struct nvkm_nvenc_fwif
gm107_nvenc_fwif[] = {
{ -1, gm107_nvenc_nofw, &gm107_nvenc },
{}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/priv.h
index 4130a2bfbb..7917affc65 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/priv.h
@@ -14,6 +14,11 @@ struct nvkm_nvenc_fwif {
const struct nvkm_nvenc_func *func;
};
+extern const struct nvkm_nvenc_fwif gm107_nvenc_fwif[];
+
int nvkm_nvenc_new_(const struct nvkm_nvenc_fwif *, struct nvkm_device *, enum nvkm_subdev_type,
int, struct nvkm_nvenc **pnvenc);
+
+int r535_nvenc_new(const struct nvkm_engine_func *, struct nvkm_device *,
+ enum nvkm_subdev_type, int, struct nvkm_nvenc **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/r535.c
new file mode 100644
index 0000000000..c8a2a9196c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/r535.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <core/object.h>
+#include <subdev/gsp.h>
+#include <engine/fifo.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>
+
+struct r535_nvenc_obj {
+ struct nvkm_object object;
+ struct nvkm_gsp_object rm;
+};
+
+static void *
+r535_nvenc_obj_dtor(struct nvkm_object *object)
+{
+ struct r535_nvenc_obj *obj = container_of(object, typeof(*obj), object);
+
+ nvkm_gsp_rm_free(&obj->rm);
+ return obj;
+}
+
+static const struct nvkm_object_func
+r535_nvenc_obj = {
+ .dtor = r535_nvenc_obj_dtor,
+};
+
+static int
+r535_nvenc_obj_ctor(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_chan *chan = nvkm_uchan_chan(oclass->parent);
+ struct r535_nvenc_obj *obj;
+ NV_MSENC_ALLOCATION_PARAMETERS *args;
+
+ if (!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_nvenc_obj, oclass, &obj->object);
+ *pobject = &obj->object;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->rm.object, oclass->handle, oclass->base.oclass,
+ sizeof(*args), &obj->rm);
+ if (WARN_ON(IS_ERR(args)))
+ return PTR_ERR(args);
+
+ args->size = sizeof(*args);
+ args->engineInstance = oclass->engine->subdev.inst;
+
+ return nvkm_gsp_rm_alloc_wr(&obj->rm, args);
+}
+
+static void *
+r535_nvenc_dtor(struct nvkm_engine *engine)
+{
+ struct nvkm_nvenc *nvenc = nvkm_nvenc(engine);
+
+ kfree(nvenc->engine.func);
+ return nvenc;
+}
+
+int
+r535_nvenc_new(const struct nvkm_engine_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_nvenc **pnvenc)
+{
+ struct nvkm_engine_func *rm;
+ int nclass;
+
+ for (nclass = 0; hw->sclass[nclass].oclass; nclass++);
+
+ if (!(rm = kzalloc(sizeof(*rm) + (nclass + 1) * sizeof(rm->sclass[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_nvenc_dtor;
+ for (int i = 0; i < nclass; i++) {
+ rm->sclass[i].minver = hw->sclass[i].minver;
+ rm->sclass[i].maxver = hw->sclass[i].maxver;
+ rm->sclass[i].oclass = hw->sclass[i].oclass;
+ rm->sclass[i].ctor = r535_nvenc_obj_ctor;
+ }
+
+ if (!(*pnvenc = kzalloc(sizeof(**pnvenc), GFP_KERNEL))) {
+ kfree(rm);
+ return -ENOMEM;
+ }
+
+ return nvkm_engine_ctor(rm, device, type, inst, true, &(*pnvenc)->engine);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/tu102.c
new file mode 100644
index 0000000000..933864423b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/tu102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+tu102_nvenc = {
+ .sclass = {
+ { -1, -1, NVC4B7_VIDEO_ENCODER },
+ {}
+ }
+};
+
+int
+tu102_nvenc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvenc **pnvenc)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvenc_new(&tu102_nvenc, device, type, inst, pnvenc);
+
+ return nvkm_nvenc_new_(gm107_nvenc_fwif, device, type, inst, pnvenc);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/Kbuild
new file mode 100644
index 0000000000..1408f664ad
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/Kbuild
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: MIT
+nvkm-y += nvkm/engine/nvjpg/ga100.o
+nvkm-y += nvkm/engine/nvjpg/ad102.o
+
+nvkm-y += nvkm/engine/nvjpg/r535.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ad102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ad102.c
new file mode 100644
index 0000000000..62705dc649
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ad102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ad102_nvjpg = {
+ .sclass = {
+ { -1, -1, NVC9D1_VIDEO_NVJPG },
+ {}
+ }
+};
+
+int
+ad102_nvjpg_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvjpg_new(&ad102_nvjpg, device, type, inst, pengine);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ga100.c
new file mode 100644
index 0000000000..f550eb07da
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/ga100.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ga100_nvjpg = {
+ .sclass = {
+ { -1, -1, NVC4D1_VIDEO_NVJPG },
+ {}
+ }
+};
+
+int
+ga100_nvjpg_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_nvjpg_new(&ga100_nvjpg, device, type, inst, pengine);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/priv.h
new file mode 100644
index 0000000000..1e80cf7003
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/priv.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_NVJPG_PRIV_H__
+#define __NVKM_NVJPG_PRIV_H__
+#include <engine/nvjpg.h>
+
+int r535_nvjpg_new(const struct nvkm_engine_func *, struct nvkm_device *,
+ enum nvkm_subdev_type, int, struct nvkm_engine **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/r535.c
new file mode 100644
index 0000000000..1babddc4eb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvjpg/r535.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <core/object.h>
+#include <subdev/gsp.h>
+#include <engine/fifo.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>
+
+struct r535_nvjpg_obj {
+ struct nvkm_object object;
+ struct nvkm_gsp_object rm;
+};
+
+static void *
+r535_nvjpg_obj_dtor(struct nvkm_object *object)
+{
+ struct r535_nvjpg_obj *obj = container_of(object, typeof(*obj), object);
+
+ nvkm_gsp_rm_free(&obj->rm);
+ return obj;
+}
+
+static const struct nvkm_object_func
+r535_nvjpg_obj = {
+ .dtor = r535_nvjpg_obj_dtor,
+};
+
+static int
+r535_nvjpg_obj_ctor(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_chan *chan = nvkm_uchan_chan(oclass->parent);
+ struct r535_nvjpg_obj *obj;
+ NV_NVJPG_ALLOCATION_PARAMETERS *args;
+
+ if (!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_nvjpg_obj, oclass, &obj->object);
+ *pobject = &obj->object;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->rm.object, oclass->handle, oclass->base.oclass,
+ sizeof(*args), &obj->rm);
+ if (WARN_ON(IS_ERR(args)))
+ return PTR_ERR(args);
+
+ args->size = sizeof(*args);
+ args->engineInstance = oclass->engine->subdev.inst;
+
+ return nvkm_gsp_rm_alloc_wr(&obj->rm, args);
+}
+
+static void *
+r535_nvjpg_dtor(struct nvkm_engine *engine)
+{
+ kfree(engine->func);
+ return engine;
+}
+
+int
+r535_nvjpg_new(const struct nvkm_engine_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_engine **pengine)
+{
+ struct nvkm_engine_func *rm;
+ int nclass, ret;
+
+ for (nclass = 0; hw->sclass[nclass].oclass; nclass++);
+
+ if (!(rm = kzalloc(sizeof(*rm) + (nclass + 1) * sizeof(rm->sclass[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_nvjpg_dtor;
+ for (int i = 0; i < nclass; i++) {
+ rm->sclass[i].minver = hw->sclass[i].minver;
+ rm->sclass[i].maxver = hw->sclass[i].maxver;
+ rm->sclass[i].oclass = hw->sclass[i].oclass;
+ rm->sclass[i].ctor = r535_nvjpg_obj_ctor;
+ }
+
+ ret = nvkm_engine_new_(rm, device, type, inst, true, pengine);
+ if (ret)
+ kfree(rm);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ofa/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/Kbuild
new file mode 100644
index 0000000000..99f1713d7e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/Kbuild
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: MIT
+nvkm-y += nvkm/engine/ofa/ga100.o
+nvkm-y += nvkm/engine/ofa/ga102.o
+nvkm-y += nvkm/engine/ofa/ad102.o
+
+nvkm-y += nvkm/engine/ofa/r535.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ad102.c b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ad102.c
new file mode 100644
index 0000000000..7ac87ef26a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ad102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ad102_ofa = {
+ .sclass = {
+ { -1, -1, NVC9FA_VIDEO_OFA },
+ {}
+ }
+};
+
+int
+ad102_ofa_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_ofa_new(&ad102_ofa, device, type, inst, pengine);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga100.c
new file mode 100644
index 0000000000..ef474f61a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga100.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ga100_ofa = {
+ .sclass = {
+ { -1, -1, NVC6FA_VIDEO_OFA },
+ {}
+ }
+};
+
+int
+ga100_ofa_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_ofa_new(&ga100_ofa, device, type, inst, pengine);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga102.c
new file mode 100644
index 0000000000..bea2555299
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/ga102.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <subdev/gsp.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+ga102_ofa = {
+ .sclass = {
+ { -1, -1, NVC7FA_VIDEO_OFA },
+ {}
+ }
+};
+
+int
+ga102_ofa_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+{
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_ofa_new(&ga102_ofa, device, type, inst, pengine);
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ofa/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/priv.h
new file mode 100644
index 0000000000..caf29e6bdd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/priv.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_OFA_PRIV_H__
+#define __NVKM_OFA_PRIV_H__
+#include <engine/ofa.h>
+
+int r535_ofa_new(const struct nvkm_engine_func *, struct nvkm_device *,
+ enum nvkm_subdev_type, int, struct nvkm_engine **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ofa/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/r535.c
new file mode 100644
index 0000000000..438dc692ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ofa/r535.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+#include <core/object.h>
+#include <subdev/gsp.h>
+#include <subdev/mmu.h>
+#include <engine/fifo.h>
+
+#include <nvrm/nvtypes.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>
+
+struct r535_ofa_obj {
+ struct nvkm_object object;
+ struct nvkm_gsp_object rm;
+};
+
+static void *
+r535_ofa_obj_dtor(struct nvkm_object *object)
+{
+ struct r535_ofa_obj *obj = container_of(object, typeof(*obj), object);
+
+ nvkm_gsp_rm_free(&obj->rm);
+ return obj;
+}
+
+static const struct nvkm_object_func
+r535_ofa_obj = {
+ .dtor = r535_ofa_obj_dtor,
+};
+
+static int
+r535_ofa_obj_ctor(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_chan *chan = nvkm_uchan_chan(oclass->parent);
+ struct r535_ofa_obj *obj;
+ NV_OFA_ALLOCATION_PARAMETERS *args;
+
+ if (!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&r535_ofa_obj, oclass, &obj->object);
+ *pobject = &obj->object;
+
+ args = nvkm_gsp_rm_alloc_get(&chan->rm.object, oclass->handle, oclass->base.oclass,
+ sizeof(*args), &obj->rm);
+ if (WARN_ON(IS_ERR(args)))
+ return PTR_ERR(args);
+
+ args->size = sizeof(*args);
+
+ return nvkm_gsp_rm_alloc_wr(&obj->rm, args);
+}
+
+static void *
+r535_ofa_dtor(struct nvkm_engine *engine)
+{
+ kfree(engine->func);
+ return engine;
+}
+
+int
+r535_ofa_new(const struct nvkm_engine_func *hw, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_engine **pengine)
+{
+ struct nvkm_engine_func *rm;
+ int nclass, ret;
+
+ for (nclass = 0; hw->sclass[nclass].oclass; nclass++);
+
+ if (!(rm = kzalloc(sizeof(*rm) + (nclass + 1) * sizeof(rm->sclass[0]), GFP_KERNEL)))
+ return -ENOMEM;
+
+ rm->dtor = r535_ofa_dtor;
+ for (int i = 0; i < nclass; i++) {
+ rm->sclass[i].minver = hw->sclass[i].minver;
+ rm->sclass[i].maxver = hw->sclass[i].maxver;
+ rm->sclass[i].oclass = hw->sclass[i].oclass;
+ rm->sclass[i].ctor = r535_ofa_obj_ctor;
+ }
+
+ ret = nvkm_engine_new_(rm, device, type, inst, true, pengine);
+ if (ret)
+ kfree(rm);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
index 8fe0444f76..131db2645f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
@@ -462,7 +462,7 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon *perfmon,
args->v0.id = di;
args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom);
- strncpy(args->v0.name, dom->name, sizeof(args->v0.name) - 1);
+ strscpy(args->v0.name, dom->name, sizeof(args->v0.name));
/* Currently only global counters (PCOUNTER) are implemented
* but this will be different for local counters (MP). */
@@ -513,8 +513,7 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon *perfmon,
snprintf(args->v0.name, sizeof(args->v0.name),
"/%s/%02x", dom->name, si);
} else {
- strncpy(args->v0.name, sig->name,
- sizeof(args->v0.name) - 1);
+ strscpy(args->v0.name, sig->name, sizeof(args->v0.name));
}
args->v0.signal = si;
@@ -572,7 +571,7 @@ nvkm_perfmon_mthd_query_source(struct nvkm_perfmon *perfmon,
args->v0.source = sig->source[si];
args->v0.mask = src->mask;
- strncpy(args->v0.name, src->name, sizeof(args->v0.name) - 1);
+ strscpy(args->v0.name, src->name, sizeof(args->v0.name));
}
if (++si < source_nr) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
index 6ae25d3e7f..c011227f70 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
@@ -82,7 +82,7 @@ struct nvkm_perfdom {
u8 mode;
u32 clk;
u16 signal_nr;
- struct nvkm_perfsig signal[];
+ struct nvkm_perfsig signal[] __counted_by(signal_nr);
};
struct nvkm_funcdom {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
index 19feadb1f6..b43b7e5e27 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
@@ -4,3 +4,5 @@ nvkm-y += nvkm/engine/sec2/gp102.o
nvkm-y += nvkm/engine/sec2/gp108.o
nvkm-y += nvkm/engine/sec2/tu102.o
nvkm-y += nvkm/engine/sec2/ga102.o
+
+nvkm-y += nvkm/engine/sec2/r535.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c
index 945abb8156..54be7596b0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c
@@ -21,6 +21,7 @@
*/
#include "priv.h"
#include <subdev/acr.h>
+#include <subdev/gsp.h>
#include <subdev/vfn.h>
#include <nvfw/flcn.h>
@@ -193,5 +194,10 @@ ga102_sec2_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
/* TOP info wasn't updated on Turing to reflect the PRI
* address change for some reason. We override it here.
*/
- return nvkm_sec2_new_(ga102_sec2_fwif, device, type, inst, 0x840000, psec2);
+ const u32 addr = 0x840000;
+
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_sec2_new(&ga102_sec2, device, type, inst, addr, psec2);
+
+ return nvkm_sec2_new_(ga102_sec2_fwif, device, type, inst, addr, psec2);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
index 172d2705c1..e158a40a4f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
@@ -4,6 +4,9 @@
#include <engine/sec2.h>
struct nvkm_acr_lsfw;
+int r535_sec2_new(const struct nvkm_sec2_func *,
+ struct nvkm_device *, enum nvkm_subdev_type, int, u32 addr, struct nvkm_sec2 **);
+
struct nvkm_sec2_func {
const struct nvkm_falcon_func *flcn;
u8 unit_unload;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/r535.c
new file mode 100644
index 0000000000..83a6bad596
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/r535.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 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 "priv.h"
+
+static void *
+r535_sec2_dtor(struct nvkm_engine *engine)
+{
+ struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
+
+ nvkm_falcon_dtor(&sec2->falcon);
+ return sec2;
+}
+
+static const struct nvkm_engine_func
+r535_sec2 = {
+ .dtor = r535_sec2_dtor,
+};
+
+int
+r535_sec2_new(const struct nvkm_sec2_func *func, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, u32 addr, struct nvkm_sec2 **psec2)
+{
+ struct nvkm_sec2 *sec2;
+ int ret;
+
+ if (!(sec2 = *psec2 = kzalloc(sizeof(*sec2), GFP_KERNEL)))
+ return -ENOMEM;
+
+ ret = nvkm_engine_ctor(&r535_sec2, device, type, inst, true, &sec2->engine);
+ if (ret)
+ return ret;
+
+ return nvkm_falcon_ctor(func->flcn, &sec2->engine.subdev, sec2->engine.subdev.name,
+ addr, &sec2->falcon);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
index 0afc4b2fa5..20452046d7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
@@ -21,6 +21,7 @@
*/
#include "priv.h"
#include <subdev/acr.h>
+#include <subdev/gsp.h>
#include <nvfw/sec2.h>
@@ -82,5 +83,10 @@ tu102_sec2_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
/* TOP info wasn't updated on Turing to reflect the PRI
* address change for some reason. We override it here.
*/
- return nvkm_sec2_new_(tu102_sec2_fwif, device, type, inst, 0x840000, psec2);
+ const u32 addr = 0x840000;
+
+ if (nvkm_gsp_rm(device->gsp))
+ return r535_sec2_new(&tu102_sec2, device, type, inst, addr, psec2);
+
+ return nvkm_sec2_new_(tu102_sec2_fwif, device, type, inst, addr, psec2);
}