Lyude Paul
2023-Sep-19 21:55 UTC
[Nouveau] [PATCH v3 00/44] drm/nouveau: initial support for GSP-RM 535.54.04 (and Ada GPUs)
Hey everyone! I'm just going through and rebasing Ben's display patches so I can push them in just a moment :). (*the rest of this email can be read in Ben Skegg's voice*) The primary issue being tackled here is that, for historical reasons (we didn't know any better / couldn't make it work reliably otherwise), some operations (SOR routing, DP link training) were performed during the 2nd HW supervisor interrupt. We don't have control of the display supervisor when running on top of RM, so this needed to be untangled and fixed - which, is one of the main aims of this patch series. The ordering of this series is pretty important, so take care if/when backporting patches from it. Beyond that main goal, various other interfaces have been added or extended to provide the information that RM will need for its version of similar interfaces. Ben Skeggs (43): drm/nouveau/devinit/tu102-: remove attempt at loading PreOS drm/nouveau/imem: support allocations not preserved across suspend drm/nouveau/gr/gf100-: lose contents of global ctxbufs across suspend drm/nouveau/mmu/gp100-: always invalidate TLBs at CACHE_LEVEL_ALL drm/nouveau/kms/nv50-: fix mst payload alloc fail crashing evo drm/nouveau/disp: rearrange output methods drm/nouveau/disp: add output detect method drm/nouveau/disp: add output method to fetch edid drm/nouveau/disp: rename internal output acquire/release functions drm/nouveau/disp: shuffle to make upcoming diffs prettier drm/nouveau/disp: add acquire_dac() drm/nouveau/disp: add acquire_sor/pior() drm/nouveau/disp: update SOR routing immediately on acquire() drm/nouveau/kms/nv50-: pull some common init out of OR-specific code drm/nouveau/kms/nv50-: remove nv_encoder.audio.connector drm/nouveau/kms/nv50-: keep output state around until modeset complete drm/nouveau/kms/nv50-: move audio enable post-modeset drm/nouveau/disp: add output hdmi config method drm/nouveau/disp: move hdmi disable out of release() drm/nouveau/disp: release outputs post-modeset drm/nouveau/disp: remove SOR routing updates from supervisor drm/nouveau/disp: add output backlight control methods drm/nouveau/disp: add output lvds config method drm/nouveau/disp: add hdmi audio hal function drm/nouveau/disp: move dp aux pwr method to HAL drm/nouveau/disp: add dp aux xfer method drm/nouveau/disp: add dp rates method drm/nouveau/kms/nv50-: split DP disable+enable into two modesets drm/nouveau/kms/nv50-: flush mst disables together drm/nouveau/kms/nv50-: fixup sink D3 before tearing down link drm/nouveau/disp: add dp train method drm/nouveau/disp: move link training out of supervisor drm/nouveau/disp: add dp sst config method drm/nouveau/disp: add dp mst id get/put methods drm/nouveau/disp: move outp/conn construction to chipset code drm/nouveau/disp: move outp init/fini paths to chipset code drm/nouveau/disp/nv50-: skip DCB_OUTPUT_TV drm/nouveau/kms/nv50-: create heads based on nvkm head mask drm/nouveau/kms/nv50-: create heads after outps/conns drm/nouveau/kms/nv50-: name aux channels after their connector drm/nouveau/kms/nv50-: create connectors based on nvkm info drm/nouveau/kms/nv50-: create outputs based on nvkm info drm/nouveau/kms/nv50-: disable dcb parsing Lyude Paul (1): drm/nouveau/kms: Add INHERIT ioctl to nvkm/nvif for reading IOR state drivers/gpu/drm/nouveau/dispnv04/disp.c | 2 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 511 +++++++++++------- drivers/gpu/drm/nouveau/dispnv50/disp.h | 6 +- drivers/gpu/drm/nouveau/dispnv50/head.h | 1 + drivers/gpu/drm/nouveau/dispnv50/headc57d.c | 14 + drivers/gpu/drm/nouveau/include/nvif/conn.h | 20 +- drivers/gpu/drm/nouveau/include/nvif/if0011.h | 21 +- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 249 +++++++-- drivers/gpu/drm/nouveau/include/nvif/outp.h | 96 +++- .../drm/nouveau/include/nvkm/core/memory.h | 1 + .../drm/nouveau/include/nvkm/subdev/instmem.h | 2 +- drivers/gpu/drm/nouveau/nouveau_backlight.c | 90 +-- drivers/gpu/drm/nouveau/nouveau_bios.c | 8 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 252 ++++----- drivers/gpu/drm/nouveau/nouveau_connector.h | 3 +- drivers/gpu/drm/nouveau/nouveau_display.c | 8 +- drivers/gpu/drm/nouveau/nouveau_dp.c | 345 ++++++++++-- drivers/gpu/drm/nouveau/nouveau_encoder.h | 30 +- drivers/gpu/drm/nouveau/nvif/conn.c | 36 +- drivers/gpu/drm/nouveau/nvif/disp.c | 2 +- drivers/gpu/drm/nouveau/nvif/outp.c | 412 ++++++++++++-- drivers/gpu/drm/nouveau/nvkm/core/memory.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 146 +---- .../gpu/drm/nouveau/nvkm/engine/disp/conn.c | 10 - .../gpu/drm/nouveau/nvkm/engine/disp/conn.h | 2 - drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 362 ++++--------- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/ga102.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 17 +- .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 38 ++ .../gpu/drm/nouveau/nvkm/engine/disp/gv100.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 15 +- .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 182 ++++++- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 144 ++++- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 43 +- .../gpu/drm/nouveau/nvkm/engine/disp/tu102.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/uconn.c | 67 +-- .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 460 +++++++++++++--- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 10 +- .../drm/nouveau/nvkm/subdev/devinit/tu102.c | 12 +- .../drm/nouveau/nvkm/subdev/instmem/base.c | 19 +- .../drm/nouveau/nvkm/subdev/instmem/priv.h | 1 + .../drm/nouveau/nvkm/subdev/mmu/vmmgp100.c | 2 +- .../drm/nouveau/nvkm/subdev/mmu/vmmtu102.c | 2 +- 50 files changed, 2461 insertions(+), 1207 deletions(-) -- 2.41.0
Lyude Paul
2023-Sep-19 21:55 UTC
[Nouveau] [PATCH v3 01/44] drm/nouveau/devinit/tu102-: remove attempt at loading PreOS
From: Ben Skeggs <bskeggs at redhat.com>>From Turing, HW will already have handled this and locked-down thefalcon before we get control. So this *should* be a no-op. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c index 81a1ad2c88a7e..40997ad1d101c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c @@ -83,17 +83,9 @@ tu102_devinit_wait(struct nvkm_device *device) } int -tu102_devinit_post(struct nvkm_devinit *base, bool post) +tu102_devinit_post(struct nvkm_devinit *init, bool post) { - struct nv50_devinit *init = nv50_devinit(base); - int ret; - - ret = tu102_devinit_wait(init->base.subdev.device); - if (ret) - return ret; - - gm200_devinit_preos(init, post); - return 0; + return tu102_devinit_wait(init->subdev.device); } static const struct nvkm_devinit_func -- 2.41.0
Lyude Paul
2023-Sep-19 21:55 UTC
[Nouveau] [PATCH v3 02/44] drm/nouveau/imem: support allocations not preserved across suspend
From: Ben Skeggs <bskeggs at redhat.com> Will initially be used to tag some large grctx allocations which don't need to be saved, to speedup suspend/resume. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- .../drm/nouveau/include/nvkm/core/memory.h | 1 + .../drm/nouveau/include/nvkm/subdev/instmem.h | 2 +- drivers/gpu/drm/nouveau/nvkm/core/memory.c | 15 +++++++++++++-- .../drm/nouveau/nvkm/subdev/instmem/base.c | 19 ++++++++++++++----- .../drm/nouveau/nvkm/subdev/instmem/priv.h | 1 + 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h index d3b6a68ddda36..fc0f389813916 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h @@ -12,6 +12,7 @@ struct nvkm_tags { }; enum nvkm_memory_target { + NVKM_MEM_TARGET_INST_SR_LOST, /* instance memory - not preserved across suspend */ NVKM_MEM_TARGET_INST, /* instance memory */ NVKM_MEM_TARGET_VRAM, /* video memory */ NVKM_MEM_TARGET_HOST, /* coherent system memory */ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index fcdaefc99fe85..92a36ddfc29ff 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -26,7 +26,7 @@ struct nvkm_instmem { u32 nvkm_instmem_rd32(struct nvkm_instmem *, u32 addr); void nvkm_instmem_wr32(struct nvkm_instmem *, u32 addr, u32 data); -int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, +int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, bool preserve, struct nvkm_memory **); int nvkm_instobj_wrap(struct nvkm_device *, struct nvkm_memory *, struct nvkm_memory **); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/memory.c b/drivers/gpu/drm/nouveau/nvkm/core/memory.c index c69daac9bac7b..a705c2dfca809 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/memory.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/memory.c @@ -140,12 +140,23 @@ nvkm_memory_new(struct nvkm_device *device, enum nvkm_memory_target target, { struct nvkm_instmem *imem = device->imem; struct nvkm_memory *memory; + bool preserve = true; int ret; - if (unlikely(target != NVKM_MEM_TARGET_INST || !imem)) + if (unlikely(!imem)) return -ENOSYS; - ret = nvkm_instobj_new(imem, size, align, zero, &memory); + switch (target) { + case NVKM_MEM_TARGET_INST_SR_LOST: + preserve = false; + break; + case NVKM_MEM_TARGET_INST: + break; + default: + return -ENOSYS; + } + + ret = nvkm_instobj_new(imem, size, align, zero, preserve, &memory); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index e0e4f97be0294..24886eabe8dc3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -94,15 +94,21 @@ nvkm_instobj_wrap(struct nvkm_device *device, struct nvkm_memory *memory, struct nvkm_memory **pmemory) { struct nvkm_instmem *imem = device->imem; + int ret; if (!imem->func->memory_wrap) return -ENOSYS; - return imem->func->memory_wrap(imem, memory, pmemory); + ret = imem->func->memory_wrap(imem, memory, pmemory); + if (ret) + return ret; + + container_of(*pmemory, struct nvkm_instobj, memory)->preserve = true; + return 0; } int -nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, +nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, bool preserve, struct nvkm_memory **pmemory) { struct nvkm_subdev *subdev = &imem->subdev; @@ -130,6 +136,7 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, nvkm_done(memory); } + container_of(memory, struct nvkm_instobj, memory)->preserve = preserve; done: if (ret) nvkm_memory_unref(&memory); @@ -176,9 +183,11 @@ nvkm_instmem_fini(struct nvkm_subdev *subdev, bool suspend) if (suspend) { list_for_each_entry(iobj, &imem->list, head) { - int ret = nvkm_instobj_save(iobj); - if (ret) - return ret; + if (iobj->preserve) { + int ret = nvkm_instobj_save(iobj); + if (ret) + return ret; + } } nvkm_bar_bar2_fini(subdev->device); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index fe92986a38858..390ca00ab5678 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -25,6 +25,7 @@ void nvkm_instmem_boot(struct nvkm_instmem *); struct nvkm_instobj { struct nvkm_memory memory; struct list_head head; + bool preserve; u32 *suspend; }; -- 2.41.0
Lyude Paul
2023-Sep-19 21:55 UTC
[Nouveau] [PATCH v3 03/44] drm/nouveau/gr/gf100-: lose contents of global ctxbufs across suspend
From: Ben Skeggs <bskeggs at redhat.com> Some of these buffers are quite large, and there's no need to preserve them across suspend. Mark the contents as lost to speedup suspend/resume. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 3648868bb9fc5..c494a1ff2d572 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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:55 UTC
[Nouveau] [PATCH v3 04/44] drm/nouveau/mmu/gp100-: always invalidate TLBs at CACHE_LEVEL_ALL
From: Ben Skeggs <bskeggs at redhat.com> Fixes some issues when running on top of RM. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c index f3630d0e0d55d..bddac77f48f06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c @@ -558,7 +558,7 @@ gp100_vmm_invalidate_pdb(struct nvkm_vmm *vmm, u64 addr) void gp100_vmm_flush(struct nvkm_vmm *vmm, int depth) { - u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24; + u32 type = 0; if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ type |= 0x00000001; /* PAGE_ALL */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c index 6cb5eefa45e9a..0095d58d4d9a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c @@ -27,7 +27,7 @@ static void tu102_vmm_flush(struct nvkm_vmm *vmm, int depth) { struct nvkm_device *device = vmm->mmu->subdev.device; - u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24; + u32 type = 0; type |= 0x00000001; /* PAGE_ALL */ if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR])) -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 05/44] drm/nouveau/kms/nv50-: fix mst payload alloc fail crashing evo
From: Ben Skeggs <bskeggs at redhat.com> Programming -1 (vc_start_slot, if alloc fails) into HW probably isn't the best idea. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 39e9ba4139c7d..889ff667d0293 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -916,23 +916,27 @@ nv50_msto_prepare(struct drm_atomic_state *state, struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; struct drm_dp_mst_atomic_payload *payload; + int ret = 0; NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); payload = drm_atomic_get_mst_payload_state(mst_state, mstc->port); - // TODO: Figure out if we want to do a better job of handling VCPI allocation failures here? if (msto->disabled) { drm_dp_remove_payload_part1(mgr, mst_state, payload); - nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); + ret = 1; } else { if (msto->enabled) - drm_dp_add_payload_part1(mgr, mst_state, payload); + ret = drm_dp_add_payload_part1(mgr, mst_state, payload); + } + if (ret == 0) { nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, payload->vc_start_slot, payload->time_slots, payload->pbn, payload->time_slots * mst_state->pbn_div); + } else { + nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); } } -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 06/44] drm/nouveau/disp: rearrange output methods
From: Ben Skeggs <bskeggs at redhat.com> - preparation for a bunch of API changes, to make diffs prettier Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 19 +++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 12 ++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 16d4ad5023a3e..7c56f653070c9 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -12,14 +12,17 @@ union nvif_outp_args { } v0; }; -#define NVIF_OUTP_V0_LOAD_DETECT 0x00 -#define NVIF_OUTP_V0_ACQUIRE 0x01 -#define NVIF_OUTP_V0_RELEASE 0x02 -#define NVIF_OUTP_V0_INFOFRAME 0x03 -#define NVIF_OUTP_V0_HDA_ELD 0x04 -#define NVIF_OUTP_V0_DP_AUX_PWR 0x05 -#define NVIF_OUTP_V0_DP_RETRAIN 0x06 -#define NVIF_OUTP_V0_DP_MST_VCPI 0x07 +#define NVIF_OUTP_V0_ACQUIRE 0x11 +#define NVIF_OUTP_V0_RELEASE 0x12 + +#define NVIF_OUTP_V0_LOAD_DETECT 0x20 + +#define NVIF_OUTP_V0_INFOFRAME 0x60 +#define NVIF_OUTP_V0_HDA_ELD 0x61 + +#define NVIF_OUTP_V0_DP_AUX_PWR 0x70 +#define NVIF_OUTP_V0_DP_RETRAIN 0x73 +#define NVIF_OUTP_V0_DP_MST_VCPI 0x78 union nvif_outp_load_detect_args { struct nvif_outp_load_detect_v0 { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index fc283a4a1522a..440ea52cc7d2b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -279,11 +279,11 @@ 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_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); default: break; } @@ -295,8 +295,8 @@ static int nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) { switch (mthd) { - case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(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_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc); default: break; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 07/44] drm/nouveau/disp: add output detect method
From: Ben Skeggs <bskeggs at redhat.com> This will check the relevant hotplug pin and skip the DDC probe we currently do if a display is present. - preparation for GSP-RM. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/conn.h | 5 -- drivers/gpu/drm/nouveau/include/nvif/if0011.h | 11 ---- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 12 ++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 9 +++ drivers/gpu/drm/nouveau/nouveau_connector.c | 60 ++++++++++++------- drivers/gpu/drm/nouveau/nouveau_dp.c | 10 +--- drivers/gpu/drm/nouveau/nvif/conn.c | 14 ----- drivers/gpu/drm/nouveau/nvif/outp.c | 25 ++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 28 +++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 6 ++ .../gpu/drm/nouveau/nvkm/engine/disp/uconn.c | 41 ------------- .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 24 ++++++++ 13 files changed, 145 insertions(+), 101 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h index dc355e1dfafa0..8a6017a358976 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/conn.h +++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h @@ -18,11 +18,6 @@ nvif_conn_id(struct nvif_conn *conn) return conn->object.handle; } -#define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */ -#define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1 -#define NVIF_CONN_HPD_STATUS_PRESENT 2 -int nvif_conn_hpd_status(struct nvif_conn *); - int nvif_conn_event_ctor(struct nvif_conn *, const char *name, nvif_event_func, u8 types, struct nvif_event *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h index 69b0b779f9424..0c25288a5a789 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h @@ -20,15 +20,4 @@ union nvif_conn_event_args { __u8 pad02[6]; } v0; }; - -#define NVIF_CONN_V0_HPD_STATUS 0x00000000 - -union nvif_conn_hpd_status_args { - struct nvif_conn_hpd_status_v0 { - __u8 version; - __u8 support; - __u8 present; - __u8 pad03[5]; - } v0; -}; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 7c56f653070c9..923bc30af2a92 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -12,6 +12,8 @@ union nvif_outp_args { } v0; }; +#define NVIF_OUTP_V0_DETECT 0x00 + #define NVIF_OUTP_V0_ACQUIRE 0x11 #define NVIF_OUTP_V0_RELEASE 0x12 @@ -24,6 +26,16 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DP_RETRAIN 0x73 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 +union nvif_outp_detect_args { + struct nvif_outp_detect_v0 { + __u8 version; +#define NVIF_OUTP_DETECT_V0_NOT_PRESENT 0x00 +#define NVIF_OUTP_DETECT_V0_PRESENT 0x01 +#define NVIF_OUTP_DETECT_V0_UNKNOWN 0x02 + __u8 status; + } v0; +}; + union nvif_outp_load_detect_args { struct nvif_outp_load_detect_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index fa76a7b5e4b37..c3e1e4d2f1a11 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -17,6 +17,15 @@ struct nvif_outp { int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct nvif_outp *); void nvif_outp_dtor(struct nvif_outp *); + +enum nvif_outp_detect_status { + NOT_PRESENT, + PRESENT, + UNKNOWN, +}; + +enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *); + int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); int nvif_outp_acquire_rgb_crt(struct nvif_outp *); int nvif_outp_acquire_tmds(struct nvif_outp *, int head, diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 68b4fb4bec63f..a290a2844547c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -413,6 +413,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct pci_dev *pdev = to_pci_dev(dev->dev); + struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL, *found = NULL; struct drm_encoder *encoder; int ret; @@ -421,33 +422,48 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) drm_connector_for_each_possible_encoder(connector, encoder) { nv_encoder = nouveau_encoder(encoder); - switch (nv_encoder->dcb->type) { - case DCB_OUTPUT_DP: - ret = nouveau_dp_detect(nouveau_connector(connector), - nv_encoder); - if (ret == NOUVEAU_DP_MST) - return NULL; - else if (ret == NOUVEAU_DP_SST) - found = nv_encoder; + if (nvif_object_constructed(&nv_encoder->outp.object)) { + enum nvif_outp_detect_status status; + + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { + ret = nouveau_dp_detect(conn, nv_encoder); + if (ret == NOUVEAU_DP_MST) + return NULL; + if (ret != NOUVEAU_DP_SST) + continue; + + return nv_encoder; + } else { + status = nvif_outp_detect(&nv_encoder->outp); + switch (status) { + case PRESENT: + return nv_encoder; + case NOT_PRESENT: + continue; + case UNKNOWN: + break; + default: + WARN_ON(1); + break; + } + } + } - break; - case DCB_OUTPUT_LVDS: + if (!nv_encoder->i2c) + continue; + + if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) { switcheroo_ddc = !!(vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC); - fallthrough; - default: - if (!nv_encoder->i2c) - break; + } - if (switcheroo_ddc) - vga_switcheroo_lock_ddc(pdev); - if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) - found = nv_encoder; - if (switcheroo_ddc) - vga_switcheroo_unlock_ddc(pdev); + if (switcheroo_ddc) + vga_switcheroo_lock_ddc(pdev); + if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) + found = nv_encoder; + if (switcheroo_ddc) + vga_switcheroo_unlock_ddc(pdev); - break; - } if (found) break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 6a4980b2d4d4e..01aa9b9c74a2a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -132,14 +132,8 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, } } - /* Check status of HPD pin before attempting an AUX transaction that - * would result in a number of (futile) retries on a connector which - * has no display plugged. - * - * TODO: look into checking this before probing I2C to detect DVI/HDMI - */ - hpd = nvif_conn_hpd_status(&nv_connector->conn); - if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) { + hpd = nvif_outp_detect(&nv_encoder->outp); + if (hpd == NOT_PRESENT) { nvif_outp_dp_aux_pwr(&nv_encoder->outp, false); goto out; } diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c index a3cf91aeae2de..879569d4ba4cc 100644 --- a/drivers/gpu/drm/nouveau/nvif/conn.c +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -45,20 +45,6 @@ nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func f return ret; } -int -nvif_conn_hpd_status(struct nvif_conn *conn) -{ - struct nvif_conn_hpd_status_v0 args; - int ret; - - args.version = 0; - - ret = nvif_mthd(&conn->object, NVIF_CONN_V0_HPD_STATUS, &args, sizeof(args)); - NVIF_ERRON(ret, &conn->object, "[HPD_STATUS] support:%d present:%d", - args.support, args.present); - return ret ? ret : !!args.support + !!args.present; -} - void nvif_conn_dtor(struct nvif_conn *conn) { diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index c24bc5eae3ecf..7f1daab35a0d2 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -210,6 +210,31 @@ nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval) return ret < 0 ? ret : args.load; } +enum nvif_outp_detect_status +nvif_outp_detect(struct nvif_outp *outp) +{ + struct nvif_outp_detect_v0 args; + int ret; + + args.version = 0; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_DETECT, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DETECT] status:%02x", args.status); + if (ret) + return UNKNOWN; + + switch (args.status) { + case NVIF_OUTP_DETECT_V0_NOT_PRESENT: return NOT_PRESENT; + case NVIF_OUTP_DETECT_V0_PRESENT: return PRESENT; + case NVIF_OUTP_DETECT_V0_UNKNOWN: return UNKNOWN; + default: + WARN_ON(1); + break; + } + + return UNKNOWN; +} + void nvif_outp_dtor(struct nvif_outp *outp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index b8ac66b4a2c4b..0d2de4769b94f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -807,6 +807,7 @@ nvkm_dp_func = { .dtor = nvkm_dp_dtor, .init = nvkm_dp_init, .fini = nvkm_dp_fini, + .detect = nvkm_outp_detect, .acquire = nvkm_dp_acquire, .release = nvkm_dp_release, .disable = nvkm_dp_disable, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 6094805fbd63b..fb061144438dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,11 +22,13 @@ * 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 @@ -207,6 +209,31 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user, bool hda) return nvkm_outp_acquire_hda(outp, type, user, false); } +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) { @@ -328,6 +355,7 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, struct nvkm_disp *disp, static const struct nvkm_outp_func nvkm_outp = { + .detect = nvkm_outp_detect, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 4e7f873f66e27..8c9fe878f3209 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -74,6 +74,9 @@ 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_detect(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 *); @@ -82,6 +85,9 @@ struct nvkm_outp_func { void *(*dtor)(struct nvkm_outp *); void (*init)(struct nvkm_outp *); void (*fini)(struct nvkm_outp *); + + int (*detect)(struct nvkm_outp *); + int (*acquire)(struct nvkm_outp *); void (*release)(struct nvkm_outp *); void (*disable)(struct nvkm_outp *, struct nvkm_ior *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c index dad942be6679c..971cccc0892cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c @@ -100,46 +100,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) { @@ -155,7 +115,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, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 440ea52cc7d2b..43752e216ce88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -275,6 +275,29 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) return ret; } +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) { @@ -295,6 +318,7 @@ static int nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) { switch (mthd) { + case NVIF_OUTP_V0_DETECT : return nvkm_uoutp_mthd_detect (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_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc); -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 08/44] drm/nouveau/disp: add output method to fetch edid
From: Ben Skeggs <bskeggs at redhat.com> - needed to support TMDS EDID on RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 10 +++++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 1 + drivers/gpu/drm/nouveau/nouveau_connector.c | 22 ++++++++------ drivers/gpu/drm/nouveau/nvif/outp.c | 30 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 15 ++++++++++ 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 923bc30af2a92..725d6e8e3d2d3 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -13,6 +13,7 @@ union nvif_outp_args { }; #define NVIF_OUTP_V0_DETECT 0x00 +#define NVIF_OUTP_V0_EDID_GET 0x01 #define NVIF_OUTP_V0_ACQUIRE 0x11 #define NVIF_OUTP_V0_RELEASE 0x12 @@ -36,6 +37,15 @@ union nvif_outp_detect_args { } v0; }; +union nvif_outp_edid_get_args { + struct nvif_outp_edid_get_v0 { + __u8 version; + __u8 pad01; + __u16 size; + __u8 data[2048]; + } v0; +}; + union nvif_outp_load_detect_args { struct nvif_outp_load_detect_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index c3e1e4d2f1a11..7c2c34a84fbd8 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -25,6 +25,7 @@ enum nvif_outp_detect_status { }; enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *); +int nvif_outp_edid_get(struct nvif_outp *, u8 **pedid); int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); int nvif_outp_acquire_rgb_crt(struct nvif_outp *); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index a290a2844547c..c079686fa2408 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -570,7 +570,6 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_encoder *nv_partner; - struct i2c_adapter *i2c; int type; int ret; enum drm_connector_status conn_status = connector_status_disconnected; @@ -593,15 +592,20 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) } nv_encoder = nouveau_connector_ddc_detect(connector); - if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { - struct edid *new_edid; + if (nv_encoder) { + struct edid *new_edid = NULL; - if ((vga_switcheroo_handler_flags() & - VGA_SWITCHEROO_CAN_SWITCH_DDC) && - nv_connector->type == DCB_CONNECTOR_LVDS) - new_edid = drm_get_edid_switcheroo(connector, i2c); - else - new_edid = drm_get_edid(connector, i2c); + if (nv_encoder->i2c) { + if ((vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) && + nv_connector->type == DCB_CONNECTOR_LVDS) + new_edid = drm_get_edid_switcheroo(connector, nv_encoder->i2c); + else + new_edid = drm_get_edid(connector, nv_encoder->i2c); + } else { + ret = nvif_outp_edid_get(&nv_encoder->outp, (u8 **)&new_edid); + if (ret < 0) + return connector_status_disconnected; + } nouveau_connector_set_edid(nv_connector, new_edid); if (!nv_connector->edid) { diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 7f1daab35a0d2..10480142eea5a 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -210,6 +210,36 @@ nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval) return ret < 0 ? ret : args.load; } +int +nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid) +{ + struct nvif_outp_edid_get_v0 *args; + int ret; + + args = kmalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + args->version = 0; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_EDID_GET, args, sizeof(*args)); + NVIF_ERRON(ret, &outp->object, "[EDID_GET] size:%d", args->size); + if (ret) + goto done; + + *pedid = kmalloc(args->size, GFP_KERNEL); + if (!*pedid) { + ret = -ENOMEM; + goto done; + } + + memcpy(*pedid, args->data, args->size); + ret = args->size; +done: + kfree(args); + return ret; +} + enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *outp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 8c9fe878f3209..1cd70868f2255 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -87,6 +87,7 @@ struct nvkm_outp_func { void (*fini)(struct nvkm_outp *); int (*detect)(struct nvkm_outp *); + int (*edid_get)(struct nvkm_outp *, u8 *data, u16 *size); int (*acquire)(struct nvkm_outp *); void (*release)(struct nvkm_outp *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 43752e216ce88..0c4ffa3ffb288 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -275,6 +275,20 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) 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) { @@ -319,6 +333,7 @@ nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc { switch (mthd) { 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_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_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc); -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 09/44] drm/nouveau/disp: rename internal output acquire/release functions
From: Ben Skeggs <bskeggs at redhat.com> These will be made static later in the patch series, after the code that uses them has been cleaned up in preparation for GSP-RM support. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 16 ++++++++-------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index fb061144438dc..3ed93df475fcc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -89,7 +89,7 @@ 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); @@ -142,7 +142,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; @@ -234,6 +234,12 @@ nvkm_outp_detect(struct nvkm_outp *outp) return ret; } +void +nvkm_outp_release(struct nvkm_outp *outp) +{ + nvkm_outp_release_or(outp, NVKM_OUTP_USER); +} + void nvkm_outp_fini(struct nvkm_outp *outp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 1cd70868f2255..76d83fb9c6e59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -77,8 +77,9 @@ void nvkm_outp_fini(struct nvkm_outp *); int nvkm_outp_detect(struct nvkm_outp *); -int nvkm_outp_acquire(struct nvkm_outp *, u8 user, bool hda); -void nvkm_outp_release(struct nvkm_outp *, u8 user); +int nvkm_outp_acquire_or(struct nvkm_outp *, u8 user, bool hda); +void nvkm_outp_release(struct nvkm_outp *); +void nvkm_outp_release_or(struct nvkm_outp *, u8 user); void nvkm_outp_route(struct nvkm_disp *); struct nvkm_outp_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 0c4ffa3ffb288..828db77af242b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -141,7 +141,7 @@ nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) ior->func->hdmi->ctrl(ior, head->id, false, 0, 0); } - nvkm_outp_release(outp, NVKM_OUTP_USER); + nvkm_outp_release(outp); return 0; } @@ -151,7 +151,7 @@ nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE] { int ret; - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda); + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hda); if (ret) return ret; @@ -172,7 +172,7 @@ nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_m if (!(outp->asy.head = nvkm_head_find(outp->disp, head))) return -EINVAL; - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hdmi && hdmi_hda); + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hdmi && hdmi_hda); if (ret) return ret; @@ -182,7 +182,7 @@ nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_m 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); + nvkm_outp_release_or(outp, NVKM_OUTP_USER); return -EINVAL; } @@ -203,7 +203,7 @@ nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) outp->lvds.dual = dual; outp->lvds.bpc8 = bpc8; - return nvkm_outp_acquire(outp, NVKM_OUTP_USER, false); + return nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); } static int @@ -219,7 +219,7 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) switch (args->v0.proto) { case NVIF_OUTP_ACQUIRE_V0_RGB_CRT: - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, false); + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); break; case NVIF_OUTP_ACQUIRE_V0_TMDS: ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head, @@ -261,7 +261,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,7 +269,7 @@ 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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 10/44] drm/nouveau/kms: Add INHERIT ioctl to nvkm/nvif for reading IOR state
Now that we're supporting things like Ada and the GSP, there's situations where we really need to actually know the display state that we're starting with when loading the driver in order to prevent breaking GSP expectations. The first step in doing this is making it so that we can read the current state of IORs from nvkm in DRM, so that we can fill in said into into the atomic state. We do this by introducing an INHERIT ioctl to nvkm/nvif. This is basically another form of ACQUIRE, except that it will only acquire the given output path for userspace if it's already set up in hardware. This way, we can go through and probe each outp object we have in DRM in order to figure out the current hardware state of each one. If the outp isn't in use, it simply returns -ENODEV. This is also part of the work that will be required for implementing GSP support for display. While the GSP should mostly work without this commit, this commit should fix some edge case bugs that can occur on initial driver load. This also paves the way for some of the initial groundwork for fastboot support. Signed-off-by: Lyude Paul <lyude at redhat.com> Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 101 ++++++++++++++++++ drivers/gpu/drm/nouveau/include/nvif/if0012.h | 23 ++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 5 + drivers/gpu/drm/nouveau/nvif/outp.c | 68 ++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 39 ++++--- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 3 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 64 +++++++++++ 8 files changed, 291 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 889ff667d0293..290f3c80ba4eb 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2519,6 +2519,104 @@ nv50_display_fini(struct drm_device *dev, bool runtime, bool suspend) cancel_work_sync(&drm->hpd_work); } +static inline void +nv50_display_read_hw_or_state(struct drm_device *dev, struct nv50_disp *disp, + struct nouveau_encoder *outp) +{ + struct drm_crtc *crtc; + struct drm_connector_list_iter conn_iter; + struct drm_connector *conn; + struct nv50_head_atom *armh; + const u32 encoder_mask = drm_encoder_mask(&outp->base.base); + bool found_conn = false, found_head = false; + u8 proto; + int head_idx; + int ret; + + switch (outp->dcb->type) { + case DCB_OUTPUT_TMDS: + ret = nvif_outp_inherit_tmds(&outp->outp, &proto); + break; + case DCB_OUTPUT_DP: + ret = nvif_outp_inherit_dp(&outp->outp, &proto); + break; + case DCB_OUTPUT_LVDS: + ret = nvif_outp_inherit_lvds(&outp->outp, &proto); + break; + case DCB_OUTPUT_ANALOG: + ret = nvif_outp_inherit_rgb_crt(&outp->outp, &proto); + break; + default: + drm_dbg_kms(dev, "Readback for %s not implemented yet, skipping\n", + outp->base.base.name); + drm_WARN_ON(dev, true); + return; + } + + if (ret < 0) + return; + + head_idx = ret; + + drm_for_each_crtc(crtc, dev) { + if (crtc->index != head_idx) + continue; + + armh = nv50_head_atom(crtc->state); + found_head = true; + break; + } + if (drm_WARN_ON(dev, !found_head)) + return; + + /* Figure out which connector is being used by this encoder */ + drm_connector_list_iter_begin(dev, &conn_iter); + nouveau_for_each_non_mst_connector_iter(conn, &conn_iter) { + if (nouveau_connector(conn)->index == outp->dcb->connector) { + found_conn = true; + break; + } + } + drm_connector_list_iter_end(&conn_iter); + if (drm_WARN_ON(dev, !found_conn)) + return; + + armh->state.encoder_mask = encoder_mask; + armh->state.connector_mask = drm_connector_mask(conn); + armh->state.active = true; + armh->state.enable = true; + pm_runtime_get_noresume(dev->dev); + + outp->crtc = crtc; + outp->ctrl = NVVAL(NV507D, SOR_SET_CONTROL, PROTOCOL, proto) | BIT(crtc->index); + + drm_connector_get(conn); + conn->state->crtc = crtc; + conn->state->best_encoder = &outp->base.base; +} + +/* Read back the currently programmed display state */ +static void +nv50_display_read_hw_state(struct nouveau_drm *drm) +{ + struct drm_device *dev = drm->dev; + struct drm_encoder *encoder; + struct drm_modeset_acquire_ctx ctx; + struct nv50_disp *disp = nv50_disp(dev); + int ret; + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + + drm_for_each_encoder(encoder, dev) { + if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) + continue; + + nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder)); + } + + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); +} + static int nv50_display_init(struct drm_device *dev, bool resume, bool runtime) { @@ -2536,6 +2634,9 @@ nv50_display_init(struct drm_device *dev, bool resume, bool runtime) } } + if (!resume) + nv50_display_read_hw_state(nouveau_drm(dev)); + return 0; } diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 725d6e8e3d2d3..6cfc885e0aa9a 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -15,6 +15,7 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DETECT 0x00 #define NVIF_OUTP_V0_EDID_GET 0x01 +#define NVIF_OUTP_V0_INHERIT 0x10 #define NVIF_OUTP_V0_ACQUIRE 0x11 #define NVIF_OUTP_V0_RELEASE 0x12 @@ -96,6 +97,28 @@ union nvif_outp_acquire_args { } v0; }; +union nvif_outp_inherit_args { + struct nvif_outp_inherit_v0 { + __u8 version; +#define NVIF_OUTP_INHERIT_V0_RGB_CRT 0x00 +#define NVIF_OUTP_INHERIT_V0_TV 0x01 +#define NVIF_OUTP_INHERIT_V0_TMDS 0x02 +#define NVIF_OUTP_INHERIT_V0_LVDS 0x03 +#define NVIF_OUTP_INHERIT_V0_DP 0x04 + // In/out. Input is one of the above values, output is the actual hw protocol + __u8 proto; + __u8 or; + __u8 link; + __u8 head; + union { + struct { + // TODO: Figure out padding, and whether we even want this field + __u8 hda; + } tmds; + }; + } v0; +}; + union nvif_outp_release_args { struct nvif_outp_release_vn { } vn; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 7c2c34a84fbd8..23776057bfea8 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -34,6 +34,11 @@ int nvif_outp_acquire_tmds(struct nvif_outp *, int head, int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], int link_nr, int link_bw, bool hda, bool mst); +int nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out); +int nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out); +int nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out); +int nvif_outp_inherit_dp(struct nvif_outp *outp, u8 *proto_out); + void nvif_outp_release(struct nvif_outp *); int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size); int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 10480142eea5a..795658f0c920c 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -196,6 +196,74 @@ nvif_outp_acquire_rgb_crt(struct nvif_outp *outp) return ret; } +static int +nvif_outp_inherit(struct nvif_outp *outp, + u8 proto, + struct nvif_outp_inherit_v0 *args, + u8 *proto_out) +{ + int ret; + + args->version = 0; + args->proto = proto; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_INHERIT, args, sizeof(*args)); + if (ret) + return ret; + + outp->or.id = args->or; + outp->or.link = args->link; + *proto_out = args->proto; + return 0; +} + +int +nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_LVDS, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:LVDS] ret:%d", ret); + return ret ?: args.head; +} + +int +nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_TMDS, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:TMDS] ret:%d", ret); + return ret ?: args.head; +} + +int +nvif_outp_inherit_dp(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_DP, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:DP] ret:%d", ret); + + // TODO: Get current link info + + return ret ?: args.head; +} + +int +nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_RGB_CRT, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:RGB_CRT] ret:%d", ret); + return ret ?: args.head; +} + int nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 0d2de4769b94f..3b6d58c154521 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -808,6 +808,7 @@ nvkm_dp_func = { .init = nvkm_dp_init, .fini = nvkm_dp_fini, .detect = nvkm_outp_detect, + .inherit = nvkm_outp_inherit, .acquire = nvkm_dp_acquire, .release = nvkm_dp_release, .disable = nvkm_dp_disable, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 3ed93df475fcc..5b55598e09c85 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -104,7 +104,7 @@ nvkm_outp_release_or(struct nvkm_outp *outp, u8 user) } } -static inline int +int nvkm_outp_acquire_ior(struct nvkm_outp *outp, u8 user, struct nvkm_ior *ior) { outp->ior = ior; @@ -247,32 +247,30 @@ nvkm_outp_fini(struct nvkm_outp *outp) outp->func->fini(outp); } -static void -nvkm_outp_init_route(struct nvkm_outp *outp) +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. */ @@ -281,10 +279,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; +} + +static void +nvkm_outp_init_route(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); @@ -362,6 +374,7 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, struct nvkm_disp *disp, static const struct nvkm_outp_func nvkm_outp = { .detect = nvkm_outp_detect, + .inherit = nvkm_outp_inherit, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 76d83fb9c6e59..ab1699b07acc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -77,7 +77,9 @@ void nvkm_outp_fini(struct nvkm_outp *); int nvkm_outp_detect(struct nvkm_outp *); +struct nvkm_ior *nvkm_outp_inherit(struct nvkm_outp *); 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); void nvkm_outp_route(struct nvkm_disp *); @@ -90,6 +92,7 @@ struct nvkm_outp_func { 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 *); void (*release)(struct nvkm_outp *); void (*disable)(struct nvkm_outp *, struct nvkm_ior *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 828db77af242b..31b76f17fa70a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -252,6 +252,69 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) return 0; } +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) + 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) { @@ -334,6 +397,7 @@ nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc switch (mthd) { 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_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc); -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 11/44] drm/nouveau/disp: shuffle to make upcoming diffs prettier
From: Ben Skeggs <bskeggs at redhat.com> - preparing to move protocol-specific args out of acquire() again - no code changes Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvif/outp.c | 106 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 74 ++++++------ 2 files changed, 91 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 795658f0c920c..eecccfc17c1c6 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -54,6 +54,28 @@ nvif_outp_dp_retrain(struct nvif_outp *outp) return ret; } +static inline int nvif_outp_acquire(struct nvif_outp *, u8, struct nvif_outp_acquire_v0 *); + +int +nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], + int link_nr, int link_bw, bool hda, bool mst) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + args.dp.link_nr = link_nr; + args.dp.link_bw = link_bw; + args.dp.hda = hda; + args.dp.mst = mst; + memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd)); + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args); + NVIF_ERRON(ret, &outp->object, + "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d", + args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link); + return ret; +} + int nvif_outp_dp_aux_pwr(struct nvif_outp *outp, bool enable) { @@ -101,48 +123,26 @@ nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_ return ret; } -void -nvif_outp_release(struct nvif_outp *outp) -{ - int ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_RELEASE, NULL, 0); - NVIF_ERRON(ret, &outp->object, "[RELEASE]"); - outp->or.id = -1; -} - -static inline int -nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 *args) -{ - int ret; - - args->version = 0; - args->proto = proto; - - ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args)); - if (ret) - return ret; - - outp->or.id = args->or; - outp->or.link = args->link; - return 0; -} - int -nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], - int link_nr, int link_bw, bool hda, bool mst) +nvif_outp_acquire_tmds(struct nvif_outp *outp, int head, + bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda) { struct nvif_outp_acquire_v0 args; int ret; - args.dp.link_nr = link_nr; - args.dp.link_bw = link_bw; - args.dp.hda = hda; - args.dp.mst = mst; - memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd)); + args.tmds.head = head; + args.tmds.hdmi = hdmi; + args.tmds.hdmi_max_ac_packet = max_ac_packet; + args.tmds.hdmi_rekey = rekey; + args.tmds.hdmi_scdc = scdc; + args.tmds.hdmi_hda = hda; - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args); + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args); NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d", - args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link); + "[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]" + " or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet, + args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda, + args.or, args.link); return ret; } @@ -162,27 +162,29 @@ nvif_outp_acquire_lvds(struct nvif_outp *outp, bool dual, bool bpc8) return ret; } -int -nvif_outp_acquire_tmds(struct nvif_outp *outp, int head, - bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda) +void +nvif_outp_release(struct nvif_outp *outp) +{ + int ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_RELEASE, NULL, 0); + NVIF_ERRON(ret, &outp->object, "[RELEASE]"); + outp->or.id = -1; +} + +static inline int +nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 *args) { - struct nvif_outp_acquire_v0 args; int ret; - args.tmds.head = head; - args.tmds.hdmi = hdmi; - args.tmds.hdmi_max_ac_packet = max_ac_packet; - args.tmds.hdmi_rekey = rekey; - args.tmds.hdmi_scdc = scdc; - args.tmds.hdmi_hda = hda; + args->version = 0; + args->proto = proto; - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args); - NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]" - " or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet, - args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda, - args.or, args.link); - return ret; + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args)); + if (ret) + return ret; + + outp->or.id = args->or; + outp->or.link = args->link; + return 0; } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 31b76f17fa70a..d56a87ae5b265 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -57,6 +57,23 @@ nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp *outp, void *argv, u32 argc) return outp->func->acquire(outp); } +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) +{ + int ret; + + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hda); + if (ret) + return ret; + + 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; + return 0; +} + static int nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc) { @@ -125,43 +142,6 @@ nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc) return -EINVAL; } -static int -nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) -{ - struct nvkm_head *head = outp->asy.head; - struct nvkm_ior *ior = outp->ior; - union nvif_outp_release_args *args = argv; - - if (argc != sizeof(args->vn)) - 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); - } - - nvkm_outp_release(outp); - 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) -{ - int ret; - - ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hda); - if (ret) - return ret; - - 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; - 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) @@ -206,6 +186,26 @@ nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) return nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); } +static int +nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) +{ + struct nvkm_head *head = outp->asy.head; + struct nvkm_ior *ior = outp->ior; + union nvif_outp_release_args *args = argv; + + if (argc != sizeof(args->vn)) + 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); + } + + nvkm_outp_release(outp); + return 0; +} + static int nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) { -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 12/44] drm/nouveau/disp: add acquire_dac()
From: Ben Skeggs <bskeggs at redhat.com> - preparing to move protocol-specific args out of acquire() again - avoid re-acquiring acquired output, will matter when enforced later - this one is basically just a rename Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 3 ++- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 5 ++--- drivers/gpu/drm/nouveau/include/nvif/outp.h | 9 ++++++++- drivers/gpu/drm/nouveau/nvif/outp.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 4 ++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 290f3c80ba4eb..62fd910ffef61 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -502,7 +502,8 @@ nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT); - nvif_outp_acquire_rgb_crt(&nv_encoder->outp); + if (!nvif_outp_acquired(&nv_encoder->outp)) + nvif_outp_acquire_dac(&nv_encoder->outp); core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh); asyh->or.depth = 0; diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 6cfc885e0aa9a..d139d070c0bc6 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -59,12 +59,11 @@ union nvif_outp_load_detect_args { union nvif_outp_acquire_args { struct nvif_outp_acquire_v0 { __u8 version; -#define NVIF_OUTP_ACQUIRE_V0_RGB_CRT 0x00 -#define NVIF_OUTP_ACQUIRE_V0_TV 0x01 +#define NVIF_OUTP_ACQUIRE_V0_DAC 0x00 #define NVIF_OUTP_ACQUIRE_V0_TMDS 0x02 #define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03 #define NVIF_OUTP_ACQUIRE_V0_DP 0x04 - __u8 proto; + __u8 type; __u8 or; __u8 link; __u8 pad04[4]; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 23776057bfea8..c6d8823ef782c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -28,7 +28,7 @@ enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *); int nvif_outp_edid_get(struct nvif_outp *, u8 **pedid); int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); -int nvif_outp_acquire_rgb_crt(struct nvif_outp *); +int nvif_outp_acquire_dac(struct nvif_outp *); int nvif_outp_acquire_tmds(struct nvif_outp *, int head, bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda); int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); @@ -40,6 +40,13 @@ int nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out); int nvif_outp_inherit_dp(struct nvif_outp *outp, u8 *proto_out); void nvif_outp_release(struct nvif_outp *); + +static inline bool +nvif_outp_acquired(struct nvif_outp *outp) +{ + return outp->or.id >= 0; +} + int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size); int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index eecccfc17c1c6..41c4de40895f0 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -171,12 +171,12 @@ nvif_outp_release(struct nvif_outp *outp) } static inline int -nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 *args) +nvif_outp_acquire(struct nvif_outp *outp, u8 type, struct nvif_outp_acquire_v0 *args) { int ret; args->version = 0; - args->proto = proto; + args->type = type; ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args)); if (ret) @@ -188,13 +188,13 @@ nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 } int -nvif_outp_acquire_rgb_crt(struct nvif_outp *outp) +nvif_outp_acquire_dac(struct nvif_outp *outp) { struct nvif_outp_acquire_v0 args; int ret; - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_RGB_CRT, &args); - NVIF_ERRON(ret, &outp->object, "[ACQUIRE proto:RGB_CRT] or:%d", args.or); + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DAC, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE DAC] or:%d", args.or); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index d56a87ae5b265..73c6227446fb8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -217,8 +217,8 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) if (outp->ior) return -EBUSY; - switch (args->v0.proto) { - case NVIF_OUTP_ACQUIRE_V0_RGB_CRT: + switch (args->v0.type) { + case NVIF_OUTP_ACQUIRE_V0_DAC: ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); break; case NVIF_OUTP_ACQUIRE_V0_TMDS: -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 13/44] drm/nouveau/disp: add acquire_sor/pior()
From: Ben Skeggs <bskeggs at redhat.com> - preparing to move protocol-specific args out of acquire() again - avoid re-acquiring acquired output, will matter when enforced later - sor/pior done at same time due to shared tmds/dp handling Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 15 ++++++---- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 7 ++++- drivers/gpu/drm/nouveau/include/nvif/outp.h | 2 ++ drivers/gpu/drm/nouveau/nvif/outp.c | 24 ++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 28 ++++++------------- 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 62fd910ffef61..814d2be34d202 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1034,7 +1034,7 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st return; if (!mstm->links++) { - /*XXX: MST audio. */ + nvif_outp_acquire_sor(&mstm->outp->outp, false /*TODO: MST audio... */); nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true); } @@ -1602,15 +1602,17 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta if ((disp->disp->object.oclass == GT214_DISP || disp->disp->object.oclass >= GF110_DISP) && + nv_encoder->dcb->type != DCB_OUTPUT_LVDS && drm_detect_monitor_audio(nv_connector->edid)) hda = true; + if (!nvif_outp_acquired(outp)) + nvif_outp_acquire_sor(outp, hda); + switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: - if (disp->disp->object.oclass == NV50_DISP || - !drm_detect_hdmi_monitor(nv_connector->edid)) - nvif_outp_acquire_tmds(outp, nv_crtc->index, false, 0, 0, 0, false); - else + if (disp->disp->object.oclass != NV50_DISP && + drm_detect_hdmi_monitor(nv_connector->edid)) nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda); if (nv_encoder->outp.or.link & 1) { @@ -1850,6 +1852,9 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st default: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT; break; } + if (!nvif_outp_acquired(&nv_encoder->outp)) + nvif_outp_acquire_pior(&nv_encoder->outp); + switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index d139d070c0bc6..57bc4b2f2b170 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -60,7 +60,9 @@ union nvif_outp_acquire_args { struct nvif_outp_acquire_v0 { __u8 version; #define NVIF_OUTP_ACQUIRE_V0_DAC 0x00 -#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x02 +#define NVIF_OUTP_ACQUIRE_V0_SOR 0x01 +#define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02 +#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x05 #define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03 #define NVIF_OUTP_ACQUIRE_V0_DP 0x04 __u8 type; @@ -68,6 +70,9 @@ union nvif_outp_acquire_args { __u8 link; __u8 pad04[4]; union { + struct { + __u8 hda; + } sor; struct { __u8 head; __u8 hdmi; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index c6d8823ef782c..a9090424dbf7e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -29,6 +29,8 @@ int nvif_outp_edid_get(struct nvif_outp *, u8 **pedid); int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); int nvif_outp_acquire_dac(struct nvif_outp *); +int nvif_outp_acquire_sor(struct nvif_outp *, bool hda); +int nvif_outp_acquire_pior(struct nvif_outp *); int nvif_outp_acquire_tmds(struct nvif_outp *, int head, bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda); int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 41c4de40895f0..81dbda52117ec 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -187,6 +187,30 @@ nvif_outp_acquire(struct nvif_outp *outp, u8 type, struct nvif_outp_acquire_v0 * return 0; } +int +nvif_outp_acquire_pior(struct nvif_outp *outp) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_PIOR, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE PIOR] or:%d", args.or); + return ret; +} + +int +nvif_outp_acquire_sor(struct nvif_outp *outp, bool hda) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + args.sor.hda = hda; + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_SOR, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE SOR] or:%d link:%d", args.or, args.link); + return ret; +} + int nvif_outp_acquire_dac(struct nvif_outp *outp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 73c6227446fb8..d71bc188047e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -61,12 +61,6 @@ 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) { - int ret; - - ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hda); - if (ret) - return ret; - memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd)); outp->dp.lt.nr = link_nr; outp->dp.lt.bw = link_bw; @@ -146,25 +140,16 @@ 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) { - struct nvkm_ior *ior; - int ret; + struct nvkm_ior *ior = outp->ior; if (!(outp->asy.head = nvkm_head_find(outp->disp, head))) return -EINVAL; - ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hdmi && hdmi_hda); - if (ret) - return ret; - - ior = outp->ior; - if (hdmi) { if (!ior->func->hdmi || hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f || - (hdmi_scdc && !ior->func->hdmi->scdc)) { - nvkm_outp_release_or(outp, NVKM_OUTP_USER); + (hdmi_scdc && !ior->func->hdmi->scdc)) return -EINVAL; - } ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey); if (ior->func->hdmi->scdc) @@ -182,8 +167,7 @@ nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) outp->lvds.dual = dual; outp->lvds.bpc8 = bpc8; - - return nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); + return 0; } static int @@ -214,13 +198,17 @@ 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.type) { case NVIF_OUTP_ACQUIRE_V0_DAC: + case NVIF_OUTP_ACQUIRE_V0_PIOR: ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); break; + case NVIF_OUTP_ACQUIRE_V0_SOR: + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda); + break; case NVIF_OUTP_ACQUIRE_V0_TMDS: ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head, args->v0.tmds.hdmi, -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 14/44] drm/nouveau/disp: update SOR routing immediately on acquire()
From: Ben Skeggs <bskeggs at redhat.com> - was previously delayed until second supervisor interrupt Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 5b55598e09c85..b288ea6658da6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -48,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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index d71bc188047e3..042a43c22061e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -235,6 +235,8 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) if (ret) return ret; + nvkm_outp_route(outp->disp); + args->v0.or = outp->ior->id; args->v0.link = outp->ior->asy.link; return 0; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 15/44] drm/nouveau/kms/nv50-: pull some common init out of OR-specific code
From: Ben Skeggs <bskeggs at redhat.com> - cleanup before additional changes Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 69 ++++++++++++----------- drivers/gpu/drm/nouveau/nouveau_encoder.h | 2 + 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 814d2be34d202..5c88d2e5321b1 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -554,34 +554,27 @@ nv50_dac_func = { }; static int -nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) +nv50_dac_create(struct nouveau_encoder *nv_encoder) { + struct drm_connector *connector = &nv_encoder->conn->base; struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nv50_disp *disp = nv50_disp(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); struct nvkm_i2c_bus *bus; - struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct dcb_output *dcbe = nv_encoder->dcb; int type = DRM_MODE_ENCODER_DAC; - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); - if (!nv_encoder) - return -ENOMEM; - nv_encoder->dcb = dcbe; - bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); if (bus) nv_encoder->i2c = &bus->i2c; encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_dac_help); drm_connector_attach_encoder(connector, encoder); - return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp); + return 0; } /* @@ -1726,13 +1719,14 @@ bool nv50_has_mst(struct nouveau_drm *drm) } static int -nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) +nv50_sor_create(struct nouveau_encoder *nv_encoder) { + struct drm_connector *connector = &nv_encoder->conn->base; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); - struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct dcb_output *dcbe = nv_encoder->dcb; struct nv50_disp *disp = nv50_disp(connector->dev); int type, ret; @@ -1745,15 +1739,9 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) break; } - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); - if (!nv_encoder) - return -ENOMEM; - nv_encoder->dcb = dcbe; nv_encoder->update = nv50_sor_update; encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_sor_help); @@ -1797,7 +1785,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) nv_encoder->i2c = &bus->i2c; } - return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp); + return 0; } /****************************************************************************** @@ -1897,8 +1885,9 @@ nv50_pior_func = { }; static int -nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) +nv50_pior_create(struct nouveau_encoder *nv_encoder) { + struct drm_connector *connector = &nv_encoder->conn->base; struct drm_device *dev = connector->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nv50_disp *disp = nv50_disp(dev); @@ -1906,8 +1895,8 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) struct nvkm_i2c_bus *bus = NULL; struct nvkm_i2c_aux *aux = NULL; struct i2c_adapter *ddc; - struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct dcb_output *dcbe = nv_encoder->dcb; int type; switch (dcbe->type) { @@ -1925,16 +1914,10 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) return -ENODEV; } - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); - if (!nv_encoder) - return -ENOMEM; - nv_encoder->dcb = dcbe; nv_encoder->i2c = ddc; nv_encoder->aux = aux; encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_pior_help); @@ -1944,7 +1927,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); nv50_outp_dump_caps(drm, nv_encoder); - return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp); + return 0; } /****************************************************************************** @@ -2797,26 +2780,46 @@ nv50_display_create(struct drm_device *dev) /* create encoder/connector objects based on VBIOS DCB table */ for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { + struct nouveau_encoder *outp; + + outp = kzalloc(sizeof(*outp), GFP_KERNEL); + if (!outp) + break; + + ret = nvif_outp_ctor(disp->disp, "kmsOutp", dcbe->id, &outp->outp); + if (ret) { + kfree(outp); + continue; + } + connector = nouveau_connector_create(dev, dcbe); - if (IS_ERR(connector)) + if (IS_ERR(connector)) { + nvif_outp_dtor(&outp->outp); + kfree(outp); continue; + } + + outp->base.base.possible_crtcs = dcbe->heads; + outp->base.base.possible_clones = 0; + outp->dcb = dcbe; + outp->conn = nouveau_connector(connector); if (dcbe->location == DCB_LOC_ON_CHIP) { switch (dcbe->type) { case DCB_OUTPUT_TMDS: case DCB_OUTPUT_LVDS: case DCB_OUTPUT_DP: - ret = nv50_sor_create(connector, dcbe); + ret = nv50_sor_create(outp); break; case DCB_OUTPUT_ANALOG: - ret = nv50_dac_create(connector, dcbe); + ret = nv50_dac_create(outp); break; default: ret = -ENODEV; break; } } else { - ret = nv50_pior_create(connector, dcbe); + ret = nv50_pior_create(outp); } if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index bcba1a14cfab6..b1554ad9d929b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -49,6 +49,8 @@ struct nouveau_encoder { struct nvif_outp outp; int or; + struct nouveau_connector *conn; + struct i2c_adapter *i2c; struct nvkm_i2c_aux *aux; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 16/44] drm/nouveau/kms/nv50-: remove nv_encoder.audio.connector
From: Ben Skeggs <bskeggs at redhat.com> - use nv_encoder.conn instead, outp->conn never changes Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 4 +--- drivers/gpu/drm/nouveau/nouveau_encoder.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 5c88d2e5321b1..a72cb74184472 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -611,7 +611,7 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id, continue; /* TODO */ nv_encoder = nouveau_encoder(encoder); - nv_connector = nouveau_connector(nv_encoder->audio.connector); + nv_connector = nv_encoder->conn; nv_crtc = nouveau_crtc(nv_encoder->crtc); if (!nv_crtc || nv_encoder->outp.or.id != port || nv_crtc->index != dev_id) @@ -723,7 +723,6 @@ nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) mutex_lock(&drm->audio.lock); if (nv_encoder->audio.enabled) { nv_encoder->audio.enabled = false; - nv_encoder->audio.connector = NULL; nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0); } mutex_unlock(&drm->audio.lock); @@ -748,7 +747,6 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld, drm_eld_size(nv_connector->base.eld)); nv_encoder->audio.enabled = true; - nv_encoder->audio.connector = &nv_connector->base; mutex_unlock(&drm->audio.lock); diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index b1554ad9d929b..ea8ef10e71aae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -62,7 +62,6 @@ struct nouveau_encoder { /* Protected by nouveau_drm.audio.lock */ struct { bool enabled; - struct drm_connector *connector; } audio; struct drm_display_mode mode; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 17/44] drm/nouveau/kms/nv50-: keep output state around until modeset complete
From: Ben Skeggs <bskeggs at redhat.com> - we'll want this info post-UPDATE for later patches Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index a72cb74184472..8fa3bb8c2f41e 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2080,7 +2080,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) nv50_crc_atomic_init_notifier_contexts(state); /* Update output path(s). */ - list_for_each_entry_safe(outp, outt, &atom->outp, head) { + list_for_each_entry(outp, &atom->outp, head) { const struct drm_encoder_helper_funcs *help; struct drm_encoder *encoder; @@ -2094,9 +2094,6 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) help->atomic_enable(encoder, state); interlock[NV50_DISP_INTERLOCK_CORE] = 1; } - - list_del(&outp->head); - kfree(outp); } /* Update head(s). */ @@ -2194,6 +2191,11 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) if (atom->lock_core) mutex_unlock(&disp->mutex); + list_for_each_entry_safe(outp, outt, &atom->outp, head) { + list_del(&outp->head); + kfree(outp); + } + /* Wait for HW to signal completion. */ for_each_new_plane_in_state(state, plane, new_plane_state, i) { struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 18/44] drm/nouveau/kms/nv50-: move audio enable post-modeset
From: Ben Skeggs <bskeggs at redhat.com> - adds tracking for post-UPDATE modeset operations, similar to mst[mo]'s - audio won't work on RM without this - we should probably have been doing this anyway Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 35 ++++++++++++++++++++++--- drivers/gpu/drm/nouveau/dispnv50/disp.h | 3 +++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 8fa3bb8c2f41e..99aa8d208711c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -707,6 +707,18 @@ nv50_audio_supported(struct drm_encoder *encoder) disp->disp->object.oclass == GT206_DISP) return false; + if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + switch (nv_encoder->dcb->type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_DP: + break; + default: + return false; + } + } + return true; } @@ -829,8 +841,6 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, size = 0; nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size); - - nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode); } /****************************************************************************** @@ -1660,8 +1670,6 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta else proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B; - nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode); - #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT backlight = nv_connector->backlight; if (backlight && backlight->uses_dpcd) @@ -1939,7 +1947,9 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) struct drm_dp_mst_topology_state *mst_state; struct nouveau_drm *drm = nouveau_drm(state->dev); struct nv50_disp *disp = nv50_disp(drm->dev); + struct nv50_atom *atom = nv50_atom(state); struct nv50_core *core = disp->core; + struct nv50_outp_atom *outp; struct nv50_mstm *mstm; int i; @@ -1962,6 +1972,21 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) if (mstm->modified) nv50_mstm_cleanup(state, mst_state, mstm); } + + list_for_each_entry(outp, &atom->outp, head) { + if (outp->encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(outp->encoder); + + if (outp->enabled) { + nv50_audio_enable(outp->encoder, nouveau_crtc(nv_encoder->crtc), + nv_encoder->conn, NULL, NULL); + outp->enabled = outp->disabled = false; + } else { + if (outp->disabled) + outp->disabled = false; + } + } + } } static void @@ -2053,6 +2078,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) if (outp->clr.mask) { help->atomic_disable(encoder, state); + outp->disabled = true; interlock[NV50_DISP_INTERLOCK_CORE] |= 1; if (outp->flush_disable) { nv50_disp_atomic_commit_wndw(state, interlock); @@ -2092,6 +2118,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) if (outp->set.mask) { help->atomic_enable(encoder, state); + outp->enabled = true; interlock[NV50_DISP_INTERLOCK_CORE] = 1; } } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index 9d66c9c726c35..42209f5b06f91 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -85,6 +85,9 @@ struct nv50_outp_atom { struct drm_encoder *encoder; bool flush_disable; + bool disabled; + bool enabled; + union nv50_outp_atom_mask { struct { bool ctrl:1; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 19/44] drm/nouveau/disp: add output hdmi config method
From: Ben Skeggs <bskeggs at redhat.com> - was previously part of acquire() - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 10 ++--- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 28 ++++++++------ drivers/gpu/drm/nouveau/include/nvif/outp.h | 5 ++- drivers/gpu/drm/nouveau/nvif/outp.c | 33 +++++++++-------- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 16 ++++++-- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 5 ++- .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 37 +++++++++---------- 7 files changed, 74 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 99aa8d208711c..7a7b3464a6671 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -778,7 +778,6 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi; union hdmi_infoframe infoframe = { 0 }; const u8 rekey = 56; /* binary driver, and tegra, constant */ - u8 scdc = 0; u32 max_ac_packet; struct { struct nvif_outp_infoframe_v0 infoframe; @@ -791,8 +790,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, max_ac_packet -= 18; /* constant from tegra */ max_ac_packet /= 32; - if (hdmi->scdc.scrambling.supported) { + if (nv_encoder->i2c && hdmi->scdc.scrambling.supported) { const bool high_tmds_clock_ratio = mode->clock > 340000; + u8 scdc; ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc); if (ret < 0) { @@ -812,8 +812,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, scdc, ret); } - ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true, - max_ac_packet, rekey, scdc, hda); + ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey, + mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported, + hdmi->scdc.scrambling.low_rates); if (ret) return; @@ -1852,7 +1853,6 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); - nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false); break; case DCB_OUTPUT_DP: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 57bc4b2f2b170..230084d675ec2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -21,6 +21,8 @@ union nvif_outp_args { #define NVIF_OUTP_V0_LOAD_DETECT 0x20 +#define NVIF_OUTP_V0_HDMI 0x50 + #define NVIF_OUTP_V0_INFOFRAME 0x60 #define NVIF_OUTP_V0_HDA_ELD 0x61 @@ -62,7 +64,6 @@ union nvif_outp_acquire_args { #define NVIF_OUTP_ACQUIRE_V0_DAC 0x00 #define NVIF_OUTP_ACQUIRE_V0_SOR 0x01 #define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02 -#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x05 #define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03 #define NVIF_OUTP_ACQUIRE_V0_DP 0x04 __u8 type; @@ -73,17 +74,6 @@ union nvif_outp_acquire_args { struct { __u8 hda; } sor; - struct { - __u8 head; - __u8 hdmi; - __u8 hdmi_max_ac_packet; - __u8 hdmi_rekey; -#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE (1 << 0) -#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4 (1 << 1) - __u8 hdmi_scdc; - __u8 hdmi_hda; - __u8 pad06[2]; - } tmds; struct { __u8 dual; __u8 bpc8; @@ -128,6 +118,20 @@ union nvif_outp_release_args { } vn; }; +union nvif_outp_hdmi_args { + struct nvif_outp_hdmi_v0 { + __u8 version; + __u8 head; + __u8 enable; + __u8 max_ac_packet; + __u8 rekey; + __u8 scdc; + __u8 scdc_scrambling; + __u8 scdc_low_rates; + __u32 khz; + } v0; +}; + union nvif_outp_infoframe_args { struct nvif_outp_infoframe_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index a9090424dbf7e..ea60d418d7f09 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -31,8 +31,6 @@ int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); int nvif_outp_acquire_dac(struct nvif_outp *); int nvif_outp_acquire_sor(struct nvif_outp *, bool hda); int nvif_outp_acquire_pior(struct nvif_outp *); -int nvif_outp_acquire_tmds(struct nvif_outp *, int head, - bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda); int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], int link_nr, int link_bw, bool hda, bool mst); @@ -49,6 +47,9 @@ nvif_outp_acquired(struct nvif_outp *outp) return outp->or.id >= 0; } +int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz, + bool scdc, bool scdc_scrambling, bool scdc_low_rates); + int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size); int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 81dbda52117ec..6e1bcc265d07f 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -124,25 +124,28 @@ nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_ } int -nvif_outp_acquire_tmds(struct nvif_outp *outp, int head, - bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda) +nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey, + u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates) { - struct nvif_outp_acquire_v0 args; + struct nvif_outp_hdmi_v0 args; int ret; - args.tmds.head = head; - args.tmds.hdmi = hdmi; - args.tmds.hdmi_max_ac_packet = max_ac_packet; - args.tmds.hdmi_rekey = rekey; - args.tmds.hdmi_scdc = scdc; - args.tmds.hdmi_hda = hda; - - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args); + args.version = 0; + args.head = head; + args.enable = enable; + args.max_ac_packet = max_ac_packet; + args.rekey = rekey; + args.khz = khz; + args.scdc = scdc; + args.scdc_scrambling = scdc_scrambling; + args.scdc_low_rates = scdc_low_rates; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI, &args, sizeof(args)); NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]" - " or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet, - args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda, - args.or, args.link); + "[HDMI head:%d enable:%d max_ac_packet:%d rekey:%d khz:%d scdc:%d " + "scdc_scrambling:%d scdc_low_rates:%d]", + args.head, args.enable, args.max_ac_packet, args.rekey, args.khz, + args.scdc, args.scdc_scrambling, args.scdc_low_rates); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 562ebae57d445..126a90805dee0 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 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index da1b1a626ef21..f8b9d16304e99 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -65,7 +65,8 @@ struct nvkm_ior_func { 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); } *hdmi; @@ -167,7 +168,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); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 042a43c22061e..8ba96323e1de5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -137,24 +137,28 @@ nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc) } 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_hdmi(struct nvkm_outp *outp, void *argv, u32 argc) { + union nvif_outp_hdmi_args *args = argv; struct nvkm_ior *ior = outp->ior; - if (!(outp->asy.head = nvkm_head_find(outp->disp, head))) + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + if (!(outp->asy.head = nvkm_head_find(outp->disp, args->v0.head))) return -EINVAL; - if (hdmi) { - if (!ior->func->hdmi || - hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f || - (hdmi_scdc && !ior->func->hdmi->scdc)) - 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; - 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); - } + 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; } @@ -209,14 +213,6 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) case NVIF_OUTP_ACQUIRE_V0_SOR: ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda); 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; @@ -370,6 +366,7 @@ 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_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_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc); -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 20/44] drm/nouveau/disp: move hdmi disable out of release()
From: Ben Skeggs <bskeggs at redhat.com> - release() is being moved post-modeset, preserve hdmi behaviour for now Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 8 ++++++++ drivers/gpu/drm/nouveau/nouveau_encoder.h | 6 +++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 15 +++++++-------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 7a7b3464a6671..ab048cf25d866 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -842,6 +842,8 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, size = 0; nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size); + + nv_encoder->hdmi.enabled = true; } /****************************************************************************** @@ -1562,6 +1564,12 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st } #endif + if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && nv_encoder->hdmi.enabled) { + nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, + false, 0, 0, 0, false, false, false); + nv_encoder->hdmi.enabled = false; + } + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr); diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index ea8ef10e71aae..b3a9415ba879c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -69,7 +69,11 @@ struct nouveau_encoder { struct nv04_output_reg restore; - union { + struct { + struct { + bool enabled; + } hdmi; + struct { struct nv50_mstm *mstm; int link_nr; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 8ba96323e1de5..ffd174091454f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -154,6 +154,13 @@ nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc) (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; + } + ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable, args->v0.max_ac_packet, args->v0.rekey); if (ior->func->hdmi->scdc) @@ -177,19 +184,11 @@ nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) static int nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) { - struct nvkm_head *head = outp->asy.head; - struct nvkm_ior *ior = outp->ior; union nvif_outp_release_args *args = argv; if (argc != sizeof(args->vn)) 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); - } - nvkm_outp_release(outp); return 0; } -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 21/44] drm/nouveau/disp: release outputs post-modeset
From: Ben Skeggs <bskeggs at redhat.com> Prior to this commit, KMS would call release() prior to modeset, and the second supervisor interrupt would update SOR routing if needed. Now, KMS will call release() post-modeset and update routing immediately. - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 18 ++++++++---------- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 2 ++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index ab048cf25d866..50a0ff304291e 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -477,7 +477,6 @@ nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); nv_encoder->crtc = NULL; - nvif_outp_release(&nv_encoder->outp); } static void @@ -1300,6 +1299,11 @@ nv50_mstm_cleanup(struct drm_atomic_state *state, } } + if (mstm->disabled) { + nvif_outp_release(&mstm->outp->outp); + mstm->disabled = false; + } + mstm->modified = false; } @@ -1334,12 +1338,6 @@ nv50_mstm_prepare(struct drm_atomic_state *state, nv50_msto_prepare(state, mst_state, &mstm->mgr, msto); } } - - if (mstm->disabled) { - if (!mstm->links) - nvif_outp_release(&mstm->outp->outp); - mstm->disabled = false; - } } static struct drm_connector * @@ -1582,7 +1580,6 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); nv50_audio_disable(encoder, nv_crtc); - nvif_outp_release(&nv_encoder->outp); nv_encoder->crtc = NULL; } @@ -1827,7 +1824,6 @@ nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); nv_encoder->crtc = NULL; - nvif_outp_release(&nv_encoder->outp); } static void @@ -1990,8 +1986,10 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) nv_encoder->conn, NULL, NULL); outp->enabled = outp->disabled = false; } else { - if (outp->disabled) + if (outp->disabled) { + nvif_outp_release(&nv_encoder->outp); outp->disabled = false; + } } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index b288ea6658da6..20a013f1bbbac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -238,6 +238,7 @@ void nvkm_outp_release(struct nvkm_outp *outp) { nvkm_outp_release_or(outp, NVKM_OUTP_USER); + nvkm_outp_route(outp->disp); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index ffd174091454f..40cbb4ddc0378 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -188,6 +188,8 @@ nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) if (argc != sizeof(args->vn)) return -ENOSYS; + if (!outp->ior) + return -EINVAL; nvkm_outp_release(outp); return 0; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 22/44] drm/nouveau/disp: remove SOR routing updates from supervisor
From: Ben Skeggs <bskeggs at redhat.com> - these shouldn't be necessary now, and are done in acquire()/release() - preparation for GSP-RM, where we don't control the supervisor Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index a48e9bdf4cd07..937baae6a3ebb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -1038,7 +1038,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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c index 4ebc030e40d12..7ac59bab6309f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c @@ -863,7 +863,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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index be81168029604..a4ce605177895 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1371,7 +1371,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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 23/44] drm/nouveau/disp: add output backlight control methods
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 17 ++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 3 + drivers/gpu/drm/nouveau/nouveau_backlight.c | 90 ++----------------- drivers/gpu/drm/nouveau/nvif/outp.c | 27 ++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/ga102.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 38 ++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/gv100.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 7 ++ .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 32 +++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 38 ++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 8 ++ .../gpu/drm/nouveau/nvkm/engine/disp/tu102.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 41 +++++++++ 22 files changed, 233 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 230084d675ec2..f878784593b43 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -21,6 +21,9 @@ union nvif_outp_args { #define NVIF_OUTP_V0_LOAD_DETECT 0x20 +#define NVIF_OUTP_V0_BL_GET 0x30 +#define NVIF_OUTP_V0_BL_SET 0x31 + #define NVIF_OUTP_V0_HDMI 0x50 #define NVIF_OUTP_V0_INFOFRAME 0x60 @@ -118,6 +121,20 @@ union nvif_outp_release_args { } vn; }; +union nvif_outp_bl_get_args { + struct nvif_outp_bl_get_v0 { + __u8 version; + __u8 level; + } v0; +}; + +union nvif_outp_bl_set_args { + struct nvif_outp_bl_set_v0 { + __u8 version; + __u8 level; + } v0; +}; + union nvif_outp_hdmi_args { struct nvif_outp_hdmi_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index ea60d418d7f09..ef63d22b62f84 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -47,6 +47,9 @@ nvif_outp_acquired(struct nvif_outp *outp) return outp->or.id >= 0; } +int nvif_outp_bl_get(struct nvif_outp *); +int nvif_outp_bl_set(struct nvif_outp *, int level); + int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates); diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 91b5ecc575380..d47442125fa18 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -109,42 +109,6 @@ nv40_backlight_init(struct nouveau_encoder *encoder, return 0; } -static int -nv50_get_intensity(struct backlight_device *bd) -{ - struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div = 1025; - u32 val; - - val = nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); - val &= NV50_PDISP_SOR_PWM_CTL_VAL; - return ((val * 100) + (div / 2)) / div; -} - -static int -nv50_set_intensity(struct backlight_device *bd) -{ - struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div = 1025; - u32 val = (bd->props.brightness * div) / 100; - - nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), - NV50_PDISP_SOR_PWM_CTL_NEW | val); - return 0; -} - -static const struct backlight_ops nv50_bl_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nv50_get_intensity, - .update_status = nv50_set_intensity, -}; - /* * eDP brightness callbacks need to happen under lock, since we need to * enable/disable the backlight ourselves for modesets @@ -238,53 +202,25 @@ static const struct backlight_ops nv50_edp_bl_ops = { }; static int -nva3_get_intensity(struct backlight_device *bd) +nv50_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div, val; - div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); - val = nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); - val &= NVA3_PDISP_SOR_PWM_CTL_VAL; - if (div && div >= val) - return ((val * 100) + (div / 2)) / div; - - return 100; + return nvif_outp_bl_get(&nv_encoder->outp); } static int -nva3_set_intensity(struct backlight_device *bd) +nv50_set_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div, val; - - div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); - val = backlight_get_brightness(bd); - if (val) - val = (val * div) / 100; - - if (div) { - nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), - val | - NV50_PDISP_SOR_PWM_CTL_NEW | - NVA3_PDISP_SOR_PWM_CTL_UNK); - return 0; - } - - return -EINVAL; + return nvif_outp_bl_set(&nv_encoder->outp, backlight_get_brightness(bd)); } -static const struct backlight_ops nva3_bl_ops = { +static const struct backlight_ops nv50_bl_ops = { .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nva3_get_intensity, - .update_status = nva3_set_intensity, + .get_brightness = nv50_get_intensity, + .update_status = nv50_set_intensity, }; /* FIXME: perform backlight probing for eDP _before_ this, this only gets called after connector @@ -298,13 +234,12 @@ nv50_backlight_init(struct nouveau_backlight *bl, const struct backlight_ops **ops) { struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; /* * Note when this runs the connectors have not been probed yet, * so nv_conn->base.status is not set yet. */ - if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1)) || + if (nvif_outp_bl_get(&nv_encoder->outp) < 0 || drm_helper_probe_detect(&nv_conn->base, NULL, false) != connector_status_connected) return -ENODEV; @@ -346,15 +281,8 @@ nv50_backlight_init(struct nouveau_backlight *bl, } } - if (drm->client.device.info.chipset <= 0xa0 || - drm->client.device.info.chipset == 0xaa || - drm->client.device.info.chipset == 0xac) - *ops = &nv50_bl_ops; - else - *ops = &nva3_bl_ops; - + *ops = &nv50_bl_ops; props->max_brightness = 100; - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 6e1bcc265d07f..5a3c0dd7d5324 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -165,6 +165,33 @@ nvif_outp_acquire_lvds(struct nvif_outp *outp, bool dual, bool bpc8) return ret; } +int +nvif_outp_bl_set(struct nvif_outp *outp, int level) +{ + struct nvif_outp_bl_set_v0 args; + int ret; + + args.version = 0; + args.level = level; + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_BL_SET, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[BL_SET level:%d]", args.level); + return ret; +} + +int +nvif_outp_bl_get(struct nvif_outp *outp) +{ + struct nvif_outp_bl_get_v0 args; + int ret; + + args.version = 0; + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_BL_GET, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[BL_GET level:%d]", args.level); + return ret ? ret : args.level; +} + void nvif_outp_release(struct nvif_outp *outp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 3b6d58c154521..0e6e388003765 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -812,6 +812,8 @@ nvkm_dp_func = { .acquire = nvkm_dp_acquire, .release = nvkm_dp_release, .disable = nvkm_dp_disable, + .bl.get = nvkm_outp_bl_get, + .bl.set = nvkm_outp_bl_set, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 23ae451ba473d..1be97a68a83ee 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 67ef889a0c5f4..843a2661ce9d8 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 52099b75f52ae..efe66ba3c61f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c @@ -105,6 +105,7 @@ ga102_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = ga102_sor_clock, + .bl = >215_sor_bl, .hdmi = &gv100_sor_hdmi, .dp = &ga102_sor_dp, .hda = &gv100_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 937baae6a3ebb..b48ead31da30e 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 = >215_sor_bl, .hdmi = &gf119_sor_hdmi, .dp = &gf119_sor_dp, .hda = &gf119_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 876a21a0cebb7..a3e2fbadade49 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 = >215_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 b4d8e868616fa..688e123ad4829 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 = >215_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 126a90805dee0..511e7831b2f58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -147,6 +147,7 @@ gm200_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_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 7f1eb4332040b..4070447bd800c 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 = >215_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 506ffbe7b8421..6318721b66f6e 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 = >215_sor_bl, .hdmi = >215_sor_hdmi, .dp = >215_sor_dp, .hda = >215_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 7ac59bab6309f..e1634f7bca56f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c @@ -212,6 +212,7 @@ gv100_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gv100_sor_hdmi, .dp = &gv100_sor_dp, .hda = &gv100_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index f8b9d16304e99..6e750890bcc93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -63,6 +63,11 @@ 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 *, u32 khz, bool support, bool scrambling, @@ -123,6 +128,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; @@ -139,6 +145,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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index f96ba4752655c..e0c5fb6df3d72 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 = >215_sor_bl, .hdmi = >215_sor_hdmi, .dp = &mcp89_sor_dp, .hda = >215_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 a4ce605177895..948a46f3a1bdf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -156,6 +156,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 +251,7 @@ nv50_sor = { .state = nv50_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, + .bl = &nv50_sor_bl, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 20a013f1bbbac..28ec7b3785130 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -209,6 +209,42 @@ nvkm_outp_acquire_or(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) { @@ -376,6 +412,8 @@ static const struct nvkm_outp_func nvkm_outp = { .detect = nvkm_outp_detect, .inherit = nvkm_outp_inherit, + .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 ab1699b07acc6..38b6b43a9f200 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -84,6 +84,9 @@ void nvkm_outp_release(struct nvkm_outp *); void nvkm_outp_release_or(struct nvkm_outp *, u8 user); void nvkm_outp_route(struct nvkm_disp *); +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 *); @@ -96,6 +99,11 @@ struct nvkm_outp_func { int (*acquire)(struct nvkm_outp *); 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; }; #define OUTP_MSG(o,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c index f5242a6722794..19f5d3a6035eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c @@ -88,6 +88,7 @@ tu102_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gv100_sor_hdmi, .dp = &tu102_sor_dp, .hda = &gv100_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 40cbb4ddc0378..c1775524919fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -181,6 +181,45 @@ nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) return 0; } +static int +nvkm_uoutp_mthd_bl_set(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; + + if (outp->func->bl.set) + ret = outp->func->bl.set(outp, args->v0.level); + else + ret = -EINVAL; + + return ret; +} + +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; + + if (outp->func->bl.get) { + ret = outp->func->bl.get(outp); + if (ret >= 0) { + args->v0.level = ret; + ret = 0; + } + } else { + ret = -EINVAL; + } + + return ret; +} + static int nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) { @@ -388,6 +427,8 @@ nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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); default: break; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 24/44] drm/nouveau/disp: add output lvds config method
From: Ben Skeggs <bskeggs at redhat.com> - was previously part of acquire() Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 16 ++++++++++------ drivers/gpu/drm/nouveau/include/nvif/outp.h | 3 ++- drivers/gpu/drm/nouveau/nvif/outp.c | 15 +++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 14 ++++++++------ 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 50a0ff304291e..11b11284a3218 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1665,7 +1665,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta lvds_8bpc = true; } - nvif_outp_acquire_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); + nvif_outp_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); break; case DCB_OUTPUT_DP: nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index f878784593b43..ee4cec541a90e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -24,6 +24,8 @@ union nvif_outp_args { #define NVIF_OUTP_V0_BL_GET 0x30 #define NVIF_OUTP_V0_BL_SET 0x31 +#define NVIF_OUTP_V0_LVDS 0x40 + #define NVIF_OUTP_V0_HDMI 0x50 #define NVIF_OUTP_V0_INFOFRAME 0x60 @@ -67,7 +69,6 @@ union nvif_outp_acquire_args { #define NVIF_OUTP_ACQUIRE_V0_DAC 0x00 #define NVIF_OUTP_ACQUIRE_V0_SOR 0x01 #define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02 -#define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03 #define NVIF_OUTP_ACQUIRE_V0_DP 0x04 __u8 type; __u8 or; @@ -77,11 +78,6 @@ union nvif_outp_acquire_args { struct { __u8 hda; } sor; - struct { - __u8 dual; - __u8 bpc8; - __u8 pad02[6]; - } lvds; struct { __u8 link_nr; /* 0 = highest possible. */ __u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */ @@ -135,6 +131,14 @@ union nvif_outp_bl_set_args { } v0; }; +union nvif_outp_lvds_args { + struct nvif_outp_lvds_v0 { + __u8 version; + __u8 dual; + __u8 bpc8; + } v0; +}; + union nvif_outp_hdmi_args { struct nvif_outp_hdmi_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index ef63d22b62f84..0ddaec9416eed 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -31,7 +31,6 @@ int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); int nvif_outp_acquire_dac(struct nvif_outp *); int nvif_outp_acquire_sor(struct nvif_outp *, bool hda); int nvif_outp_acquire_pior(struct nvif_outp *); -int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], int link_nr, int link_bw, bool hda, bool mst); int nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out); @@ -50,6 +49,8 @@ nvif_outp_acquired(struct nvif_outp *outp) int nvif_outp_bl_get(struct nvif_outp *); int nvif_outp_bl_set(struct nvif_outp *, int level); +int nvif_outp_lvds(struct nvif_outp *, bool dual, bool bpc8); + int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 5a3c0dd7d5324..dbb0986f05558 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -150,18 +150,17 @@ nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, } int -nvif_outp_acquire_lvds(struct nvif_outp *outp, bool dual, bool bpc8) +nvif_outp_lvds(struct nvif_outp *outp, bool dual, bool bpc8) { - struct nvif_outp_acquire_v0 args; + struct nvif_outp_lvds_v0 args; int ret; - args.lvds.dual = dual; - args.lvds.bpc8 = bpc8; + args.version = 0; + args.dual = dual; + args.bpc8 = bpc8; - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_LVDS, &args); - NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:LVDS dual:%d 8bpc:%d] or:%d link:%d", - args.lvds.dual, args.lvds.bpc8, args.or, args.link); + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_LVDS, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[LVDS dual:%d 8bpc:%d]", args.dual, args.bpc8); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index c1775524919fd..ad75dc5c50cf7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -171,13 +171,17 @@ nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc) } static int -nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) +nvkm_uoutp_mthd_lvds(struct nvkm_outp *outp, void *argv, u32 argc) { + union nvif_outp_lvds_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; if (outp->info.type != DCB_OUTPUT_LVDS) return -EINVAL; - outp->lvds.dual = dual; - outp->lvds.bpc8 = bpc8; + outp->lvds.dual = !!args->v0.dual; + outp->lvds.bpc8 = !!args->v0.bpc8; return 0; } @@ -253,9 +257,6 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) case NVIF_OUTP_ACQUIRE_V0_SOR: ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.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, @@ -406,6 +407,7 @@ 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_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); -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 25/44] drm/nouveau/disp: add hdmi audio hal function
From: Ben Skeggs <bskeggs at redhat.com> This just adds a hook for RM to use, HW paths remain untouched, but should probably be cleaned up to use this too at some point. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 6e750890bcc93..8686e5c044a5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -74,6 +74,7 @@ struct nvkm_ior_func { 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 { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index ad75dc5c50cf7..7574f22006441 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -99,12 +99,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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 26/44] drm/nouveau/disp: move dp aux pwr method to HAL
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 9 +++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h | 4 ++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 6 +++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 0e6e388003765..99fe7ef07a443 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -41,6 +41,14 @@ */ #define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100) +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; @@ -814,6 +822,7 @@ nvkm_dp_func = { .disable = nvkm_dp_disable, .bl.get = nvkm_outp_bl_get, .bl.set = nvkm_outp_bl_set, + .dp.aux_pwr = nvkm_dp_aux_pwr, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 38b6b43a9f200..513794a278a91 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -104,6 +104,10 @@ struct nvkm_outp_func { int (*get)(struct nvkm_outp *); int (*set)(struct nvkm_outp *, int level); } bl; + + struct { + int (*aux_pwr)(struct nvkm_outp *, bool pu); + } dp; }; #define OUTP_MSG(o,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 7574f22006441..6ca364e953bd7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -75,10 +75,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 -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 27/44] drm/nouveau/disp: add dp aux xfer method
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 32 +++++++++---------- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 12 +++++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_connector.c | 12 ++----- drivers/gpu/drm/nouveau/nouveau_encoder.h | 1 - drivers/gpu/drm/nouveau/nvif/outp.c | 24 ++++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 14 ++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 27 +++++++++++++--- 9 files changed, 94 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 11b11284a3218..ee53bc5d10042 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1704,14 +1704,13 @@ nv50_sor_destroy(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - nvif_outp_dtor(&nv_encoder->outp); - nv50_mstm_del(&nv_encoder->dp.mstm); drm_encoder_cleanup(encoder); if (nv_encoder->dcb->type == DCB_OUTPUT_DP) mutex_destroy(&nv_encoder->dp.hpd_irq_lock); + nvif_outp_dtor(&nv_encoder->outp); kfree(encoder); } @@ -1764,22 +1763,22 @@ nv50_sor_create(struct nouveau_encoder *nv_encoder) nv50_outp_dump_caps(drm, nv_encoder); if (dcbe->type == DCB_OUTPUT_DP) { - struct nvkm_i2c_aux *aux - nvkm_i2c_aux_find(i2c, dcbe->i2c_index); - mutex_init(&nv_encoder->dp.hpd_irq_lock); - if (aux) { - if (disp->disp->object.oclass < GF110_DISP) { - /* HW has no support for address-only - * transactions, so we're required to - * use custom I2C-over-AUX code. - */ - nv_encoder->i2c = &aux->i2c; - } else { - nv_encoder->i2c = &nv_connector->aux.ddc; - } - nv_encoder->aux = aux; + if (disp->disp->object.oclass < GF110_DISP) { + /* HW has no support for address-only + * transactions, so we're required to + * use custom I2C-over-AUX code. + */ + struct nvkm_i2c_aux *aux; + + aux = nvkm_i2c_aux_find(i2c, dcbe->i2c_index); + if (!aux) + return -EINVAL; + + nv_encoder->i2c = &aux->i2c; + } else { + nv_encoder->i2c = &nv_connector->aux.ddc; } if (nv_connector->type != DCB_CONNECTOR_eDP && @@ -1925,7 +1924,6 @@ nv50_pior_create(struct nouveau_encoder *nv_encoder) } nv_encoder->i2c = ddc; - nv_encoder->aux = aux; encoder = to_drm_encoder(nv_encoder); drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index ee4cec541a90e..94f1e55b0ce6c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -32,6 +32,7 @@ union nvif_outp_args { #define NVIF_OUTP_V0_HDA_ELD 0x61 #define NVIF_OUTP_V0_DP_AUX_PWR 0x70 +#define NVIF_OUTP_V0_DP_AUX_XFER 0x71 #define NVIF_OUTP_V0_DP_RETRAIN 0x73 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 @@ -182,6 +183,17 @@ union nvif_outp_dp_aux_pwr_args { } v0; }; +union nvif_outp_dp_aux_xfer_args { + struct nvif_outp_dp_aux_xfer_v0 { + __u8 version; + __u8 pad01; + __u8 type; + __u8 size; + __u32 addr; + __u8 data[16]; + } v0; +}; + union nvif_outp_dp_retrain_args { struct nvif_outp_dp_retrain_vn { } vn; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 0ddaec9416eed..dd4dd0e2a7a1d 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -56,7 +56,9 @@ int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size); int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); + int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); +int nvif_outp_dp_aux_xfer(struct nvif_outp *, u8 type, u8 *size, u32 addr, u8 *data); int nvif_outp_dp_retrain(struct nvif_outp *); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c079686fa2408..063cefe26be20 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1226,23 +1226,17 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg) struct nouveau_connector *nv_connector container_of(obj, typeof(*nv_connector), aux); struct nouveau_encoder *nv_encoder; - struct nvkm_i2c_aux *aux; u8 size = msg->size; int ret; nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); - if (!nv_encoder || !(aux = nv_encoder->aux)) + if (!nv_encoder) return -ENODEV; if (WARN_ON(msg->size > 16)) return -E2BIG; - ret = nvkm_i2c_aux_acquire(aux); - if (ret) - return ret; - - ret = nvkm_i2c_aux_xfer(aux, false, msg->request, msg->address, - msg->buffer, &size); - nvkm_i2c_aux_release(aux); + ret = nvif_outp_dp_aux_xfer(&nv_encoder->outp, + msg->request, &size, msg->address, msg->buffer); if (ret >= 0) { msg->reply = ret; return size; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index b3a9415ba879c..aacdf2814abaa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -52,7 +52,6 @@ struct nouveau_encoder { struct nouveau_connector *conn; struct i2c_adapter *i2c; - struct nvkm_i2c_aux *aux; /* different to drm_encoder.crtc, this reflects what's * actually programmed on the hw, not the proposed crtc */ diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index dbb0986f05558..df6e89379982c 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -76,6 +76,30 @@ nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], return ret; } +int +nvif_outp_dp_aux_xfer(struct nvif_outp *outp, u8 type, u8 *psize, u32 addr, u8 *data) +{ + struct nvif_outp_dp_aux_xfer_v0 args; + u8 size = *psize; + int ret; + + args.version = 0; + args.type = type; + args.size = size; + args.addr = addr; + memcpy(args.data, data, size); + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_AUX_XFER, &args, sizeof(args)); + NVIF_DEBUG(&outp->object, "[DP_AUX_XFER type:%d size:%d addr:%05x] %d size:%d (ret: %d)", + args.type, size, args.addr, ret, args.size, ret); + if (ret < 0) + return ret; + + *psize = args.size; + + memcpy(data, args.data, size); + return ret; +} + int nvif_outp_dp_aux_pwr(struct nvif_outp *outp, bool enable) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 99fe7ef07a443..49fbb32f50223 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -41,6 +41,19 @@ */ #define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100) +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) { @@ -823,6 +836,7 @@ nvkm_dp_func = { .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, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 513794a278a91..a2391b224ea49 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -107,6 +107,7 @@ struct nvkm_outp_func { struct { int (*aux_pwr)(struct nvkm_outp *, bool pu); + int (*aux_xfer)(struct nvkm_outp *, u8 type, u32 addr, u8 *data, u8 *size); } dp; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 6ca364e953bd7..cd92db9028a3d 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 @@ -68,6 +70,20 @@ nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE] 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 nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc) { @@ -429,7 +445,7 @@ 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_DETECT : return nvkm_uoutp_mthd_detect (outp, argv, argc); @@ -440,11 +456,13 @@ nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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); default: break; } - return 1; + *invalid = true; + return 0; } static int @@ -452,12 +470,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) -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 28/44] drm/nouveau/disp: add dp rates method
From: Ben Skeggs <bskeggs at redhat.com> - moves building of link rates table from NVKM to DRM - preparing to move link training out of supervisor Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 13 ++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 8 + drivers/gpu/drm/nouveau/nouveau_dp.c | 143 ++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_encoder.h | 12 +- drivers/gpu/drm/nouveau/nvif/outp.c | 21 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 66 -------- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 24 +++ 8 files changed, 189 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 94f1e55b0ce6c..ddc8e3d858235 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -33,6 +33,7 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DP_AUX_PWR 0x70 #define NVIF_OUTP_V0_DP_AUX_XFER 0x71 +#define NVIF_OUTP_V0_DP_RATES 0x72 #define NVIF_OUTP_V0_DP_RETRAIN 0x73 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 @@ -194,6 +195,18 @@ union nvif_outp_dp_aux_xfer_args { } v0; }; +union nvif_outp_dp_rates_args { + struct nvif_outp_dp_rates_v0 { + __u8 version; + __u8 pad01[6]; + __u8 rates; + struct { + __s8 dpcd; + __u32 rate; + } rate[8]; + } v0; +}; + union nvif_outp_dp_retrain_args { struct nvif_outp_dp_retrain_vn { } vn; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index dd4dd0e2a7a1d..596d543acd302 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -59,6 +59,14 @@ int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); int nvif_outp_dp_aux_xfer(struct nvif_outp *, u8 type, u8 *size, u32 addr, u8 *data); + +struct nvif_outp_dp_rate { + int dpcd; /* -1 for non-indexed rates */ + u32 rate; +}; + +int nvif_outp_dp_rates(struct nvif_outp *, struct nvif_outp_dp_rate *rate, int rate_nr); + int nvif_outp_dp_retrain(struct nvif_outp *); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 01aa9b9c74a2a..f26769bca1950 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -42,6 +42,21 @@ nouveau_dp_has_sink_count(struct drm_connector *connector, return drm_dp_read_sink_count_cap(connector, outp->dp.dpcd, &outp->dp.desc); } +static bool +nouveau_dp_probe_lttpr(struct nouveau_encoder *outp) +{ + u8 rev, size = sizeof(rev); + int ret; + + ret = nvif_outp_dp_aux_xfer(&outp->outp, DP_AUX_NATIVE_READ, &size, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + &rev); + if (ret || size < sizeof(rev) || rev < 0x14) + return false; + + return true; +} + static enum drm_connector_status nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector, struct nouveau_encoder *outp) @@ -53,10 +68,99 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector, int ret; u8 *dpcd = outp->dp.dpcd; + outp->dp.lttpr.nr = 0; + outp->dp.rate_nr = 0; + outp->dp.link_nr = 0; + outp->dp.link_bw = 0; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP && + nouveau_dp_probe_lttpr(outp) && + !drm_dp_read_dpcd_caps(aux, dpcd) && + !drm_dp_read_lttpr_common_caps(aux, dpcd, outp->dp.lttpr.caps)) { + int nr = drm_dp_lttpr_count(outp->dp.lttpr.caps); + + if (nr > 0) + outp->dp.lttpr.nr = nr; + } + ret = drm_dp_read_dpcd_caps(aux, dpcd); if (ret < 0) goto out; + outp->dp.link_nr = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + if (outp->dcb->dpconf.link_nr < outp->dp.link_nr) + outp->dp.link_nr = outp->dcb->dpconf.link_nr; + + if (outp->dp.lttpr.nr) { + int links = drm_dp_lttpr_max_lane_count(outp->dp.lttpr.caps); + + if (links && links < outp->dp.link_nr) + outp->dp.link_nr = links; + } + + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { + __le16 rates[DP_MAX_SUPPORTED_RATES]; + + ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, rates, sizeof(rates)); + if (ret == sizeof(rates)) { + for (int i = 0; i < ARRAY_SIZE(rates); i++) { + u32 rate = (le16_to_cpu(rates[i]) * 200) / 10; + int j; + + if (!rate) + break; + + for (j = 0; j < outp->dp.rate_nr; j++) { + if (rate > outp->dp.rate[j].rate) { + for (int k = outp->dp.rate_nr; k > j; k--) + outp->dp.rate[k] = outp->dp.rate[k - 1]; + break; + } + } + + outp->dp.rate[j].dpcd = i; + outp->dp.rate[j].rate = rate; + outp->dp.rate_nr++; + } + } + } + + if (!outp->dp.rate_nr) { + const u32 rates[] = { 810000, 540000, 270000, 162000 }; + u32 max_rate = dpcd[DP_MAX_LINK_RATE] * 27000; + + if (outp->dp.lttpr.nr) { + int rate = drm_dp_lttpr_max_link_rate(outp->dp.lttpr.caps); + + if (rate && rate < max_rate) + max_rate = rate; + } + + max_rate = min_t(int, max_rate, outp->dcb->dpconf.link_bw); + + for (int i = 0; i < ARRAY_SIZE(rates); i++) { + if (rates[i] <= max_rate) { + outp->dp.rate[outp->dp.rate_nr].dpcd = -1; + outp->dp.rate[outp->dp.rate_nr].rate = rates[i]; + outp->dp.rate_nr++; + } + } + + if (WARN_ON(!outp->dp.rate_nr)) + goto out; + } + + ret = nvif_outp_dp_rates(&outp->outp, outp->dp.rate, outp->dp.rate_nr); + if (ret) + goto out; + + for (int i = 0; i < outp->dp.rate_nr; i++) { + u32 link_bw = outp->dp.rate[i].rate; + + if (link_bw > outp->dp.link_bw) + outp->dp.link_bw = link_bw; + } + ret = drm_dp_read_desc(aux, &outp->dp.desc, drm_dp_is_branch(dpcd)); if (ret < 0) goto out; @@ -151,39 +255,14 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, goto out; } - nv_encoder->dp.link_bw = 27000 * dpcd[DP_MAX_LINK_RATE]; - nv_encoder->dp.link_nr - dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; - - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { - struct drm_dp_aux *aux = &nv_connector->aux; - int ret, i; - u8 sink_rates[16]; - - ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates)); - if (ret == sizeof(sink_rates)) { - for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { - int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; - if (val && (i == 0 || val > nv_encoder->dp.link_bw)) - nv_encoder->dp.link_bw = val; - } - } - } - - NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", - nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, - dpcd[DP_DPCD_REV]); - NV_DEBUG(drm, "encoder: %dx%d\n", - nv_encoder->dcb->dpconf.link_nr, - nv_encoder->dcb->dpconf.link_bw); - - if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr) - nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; - if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw) - nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw; + NV_DEBUG(drm, "sink dpcd version: 0x%02x\n", dpcd[DP_DPCD_REV]); + for (int i = 0; i < nv_encoder->dp.rate_nr; i++) + NV_DEBUG(drm, "sink rate %d: %d\n", i, nv_encoder->dp.rate[i].rate); - NV_DEBUG(drm, "maximum: %dx%d\n", - nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); + NV_DEBUG(drm, "encoder: %dx%d\n", nv_encoder->dcb->dpconf.link_nr, + nv_encoder->dcb->dpconf.link_bw); + NV_DEBUG(drm, "maximum: %dx%d\n", nv_encoder->dp.link_nr, + nv_encoder->dp.link_bw); if (mstm && mstm->can_mst) { ret = nv50_mstm_detect(nv_encoder); diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index aacdf2814abaa..123d0ecf5f586 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -75,6 +75,17 @@ struct nouveau_encoder { struct { struct nv50_mstm *mstm; + + struct { + u8 caps[DP_LTTPR_COMMON_CAP_SIZE]; + u8 nr; + } lttpr; + + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + + struct nvif_outp_dp_rate rate[8]; + int rate_nr; + int link_nr; int link_bw; @@ -83,7 +94,6 @@ struct nouveau_encoder { */ struct mutex hpd_irq_lock; - u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; struct drm_dp_desc desc; diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index df6e89379982c..050d5cd303ad4 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -76,6 +76,27 @@ nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], return ret; } +int +nvif_outp_dp_rates(struct nvif_outp *outp, struct nvif_outp_dp_rate *rate, int rate_nr) +{ + struct nvif_outp_dp_rates_v0 args; + int ret; + + if (rate_nr > ARRAY_SIZE(args.rate)) + return -EINVAL; + + args.version = 0; + args.rates = rate_nr; + for (int i = 0; i < args.rates; i++, rate++) { + args.rate[i].dpcd = rate->dpcd; + args.rate[i].rate = rate->rate; + } + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RATES, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_RATES rates:%d]", args.rates); + return ret; +} + int nvif_outp_dp_aux_xfer(struct nvif_outp *outp, u8 type, u8 *psize, u32 addr, u8 *data) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 49fbb32f50223..af0f81a2834b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -615,48 +615,6 @@ nvkm_dp_acquire(struct nvkm_outp *outp) 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); - - 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 @@ -757,34 +715,10 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) } 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) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index a2391b224ea49..5cef5933e7f25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -108,6 +108,7 @@ struct nvkm_outp_func { 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 *); } dp; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index cd92db9028a3d..fd756e4599dab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -70,6 +70,29 @@ nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE] return 0; } +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) { @@ -457,6 +480,7 @@ nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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; } -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 29/44] drm/nouveau/kms/nv50-: split DP disable+enable into two modesets
From: Ben Skeggs <bskeggs at redhat.com> Link training can finally be moved out of the supervisor sequence, but first we need to split DP modesets into separate disable and enable sequences to be able to perform link training between them instead. - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index ee53bc5d10042..48e099ed7d51c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2375,7 +2375,8 @@ nv50_disp_outp_atomic_check_clr(struct nv50_atom *atom, if (IS_ERR(outp)) return PTR_ERR(outp); - if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { + if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST || + nouveau_encoder(outp->encoder)->dcb->type == DCB_OUTPUT_DP) { outp->flush_disable = true; atom->flush_disable = true; } -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 30/44] drm/nouveau/kms/nv50-: flush mst disables together
From: Ben Skeggs <bskeggs at redhat.com> - fixes some issues tearing down modes on tiled displays Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 11 +---------- drivers/gpu/drm/nouveau/dispnv50/disp.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 48e099ed7d51c..1fcd1b36a2751 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2084,13 +2084,6 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) help->atomic_disable(encoder, state); outp->disabled = true; interlock[NV50_DISP_INTERLOCK_CORE] |= 1; - if (outp->flush_disable) { - nv50_disp_atomic_commit_wndw(state, interlock); - nv50_disp_atomic_commit_core(state, interlock); - memset(interlock, 0x00, sizeof(interlock)); - - flushed = true; - } } } @@ -2376,10 +2369,8 @@ nv50_disp_outp_atomic_check_clr(struct nv50_atom *atom, return PTR_ERR(outp); if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST || - nouveau_encoder(outp->encoder)->dcb->type == DCB_OUTPUT_DP) { - outp->flush_disable = true; + nouveau_encoder(outp->encoder)->dcb->type == DCB_OUTPUT_DP) atom->flush_disable = true; - } outp->clr.ctrl = true; atom->lock_core = true; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index 42209f5b06f91..1e5601223c753 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -83,7 +83,6 @@ struct nv50_outp_atom { struct list_head head; struct drm_encoder *encoder; - bool flush_disable; bool disabled; bool enabled; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 31/44] drm/nouveau/kms/nv50-: fixup sink D3 before tearing down link
From: Ben Skeggs <bskeggs at redhat.com> - fixes bug preventing this on SST - implement for MST Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 13 +++---------- drivers/gpu/drm/nouveau/nouveau_dp.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nouveau_encoder.h | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 1fcd1b36a2751..1ea4b113058cd 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1300,6 +1300,7 @@ nv50_mstm_cleanup(struct drm_atomic_state *state, } if (mstm->disabled) { + nouveau_dp_power_down(mstm->outp); nvif_outp_release(&mstm->outp->outp); mstm->disabled = false; } @@ -1551,7 +1552,6 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st #endif struct drm_dp_aux *aux = &nv_connector->aux; int ret; - u8 pwr; #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT if (backlight && backlight->uses_dpcd) { @@ -1568,15 +1568,8 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st nv_encoder->hdmi.enabled = false; } - if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { - ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr); - - if (ret == 0) { - pwr &= ~DP_SET_POWER_MASK; - pwr |= DP_SET_POWER_D3; - drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); - } - } + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) + nouveau_dp_power_down(nv_encoder); nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); nv50_audio_disable(encoder, nv_crtc); diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index f26769bca1950..1c0b992fe2416 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -284,6 +284,21 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, return ret; } +void +nouveau_dp_power_down(struct nouveau_encoder *outp) +{ + struct drm_dp_aux *aux = &outp->conn->aux; + int ret; + u8 pwr; + + ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr); + if (ret == 1) { + pwr &= ~DP_SET_POWER_MASK; + pwr |= DP_SET_POWER_D3; + drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); + } +} + bool nouveau_dp_link_check(struct nouveau_connector *nv_connector) { diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 123d0ecf5f586..ed31db58176c3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -155,6 +155,7 @@ enum nouveau_dp_status { }; int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *); +void nouveau_dp_power_down(struct nouveau_encoder *); bool nouveau_dp_link_check(struct nouveau_connector *); void nouveau_dp_irq(struct work_struct *); enum drm_mode_status nv50_dp_mode_valid(struct nouveau_encoder *, -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 32/44] drm/nouveau/disp: add dp train method
From: Ben Skeggs <bskeggs at redhat.com> - passes DPCD information from DRM to NVKM - removes NVKM's own sink caps handling - link still trained from supervisor, more patches to come Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 6 +- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 25 ++-- drivers/gpu/drm/nouveau/include/nvif/outp.h | 7 +- drivers/gpu/drm/nouveau/nouveau_dp.c | 75 +++++++++-- drivers/gpu/drm/nouveau/nouveau_encoder.h | 7 ++ drivers/gpu/drm/nouveau/nvif/outp.c | 38 +++--- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 118 +++--------------- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 41 +++--- 9 files changed, 143 insertions(+), 176 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 1ea4b113058cd..d8ed23ddd2e4c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1038,7 +1038,7 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st if (!mstm->links++) { nvif_outp_acquire_sor(&mstm->outp->outp, false /*TODO: MST audio... */); - nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true); + nouveau_dp_train(mstm->outp, true, 0, 0); } if (mstm->outp->outp.or.link & 1) @@ -1661,7 +1661,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta nvif_outp_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); break; case DCB_OUTPUT_DP: - nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false); + nouveau_dp_train(nv_encoder, false, mode->clock, asyh->or.bpc); depth = nv50_dp_bpc_to_depth(asyh->or.bpc); if (nv_encoder->outp.or.link & 1) @@ -1852,7 +1852,7 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st break; case DCB_OUTPUT_DP: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); - nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false); + nouveau_dp_train(nv_encoder, false, asyh->state.adjusted_mode.clock, 6); break; default: BUG(); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index ddc8e3d858235..14972b942be7e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -34,7 +34,7 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DP_AUX_PWR 0x70 #define NVIF_OUTP_V0_DP_AUX_XFER 0x71 #define NVIF_OUTP_V0_DP_RATES 0x72 -#define NVIF_OUTP_V0_DP_RETRAIN 0x73 +#define NVIF_OUTP_V0_DP_TRAIN 0x73 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 union nvif_outp_detect_args { @@ -71,7 +71,6 @@ union nvif_outp_acquire_args { #define NVIF_OUTP_ACQUIRE_V0_DAC 0x00 #define NVIF_OUTP_ACQUIRE_V0_SOR 0x01 #define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02 -#define NVIF_OUTP_ACQUIRE_V0_DP 0x04 __u8 type; __u8 or; __u8 link; @@ -80,14 +79,6 @@ union nvif_outp_acquire_args { struct { __u8 hda; } sor; - struct { - __u8 link_nr; /* 0 = highest possible. */ - __u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */ - __u8 hda; - __u8 mst; - __u8 pad04[4]; - __u8 dpcd[DP_RECEIVER_CAP_SIZE]; - } dp; }; } v0; }; @@ -207,9 +198,17 @@ union nvif_outp_dp_rates_args { } v0; }; -union nvif_outp_dp_retrain_args { - struct nvif_outp_dp_retrain_vn { - } vn; +union nvif_outp_dp_train_args { + struct nvif_outp_dp_train_v0 { + __u8 version; + __u8 retrain; + __u8 mst; + __u8 lttprs; + __u8 post_lt_adj; + __u8 link_nr; + __u32 link_bw; + __u8 dpcd[DP_RECEIVER_CAP_SIZE]; + } v0; }; union nvif_outp_dp_mst_vcpi_args { diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 596d543acd302..9a78483e0289d 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -31,8 +31,6 @@ int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); int nvif_outp_acquire_dac(struct nvif_outp *); int nvif_outp_acquire_sor(struct nvif_outp *, bool hda); int nvif_outp_acquire_pior(struct nvif_outp *); -int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], - int link_nr, int link_bw, bool hda, bool mst); int nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out); int nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out); int nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out); @@ -66,8 +64,9 @@ struct nvif_outp_dp_rate { }; int nvif_outp_dp_rates(struct nvif_outp *, struct nvif_outp_dp_rate *rate, int rate_nr); - -int nvif_outp_dp_retrain(struct nvif_outp *); +int nvif_outp_dp_train(struct nvif_outp *, u8 dpcd[DP_RECEIVER_CAP_SIZE], + u8 lttprs, u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, + bool retrain); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 1c0b992fe2416..9280daf325341 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -79,8 +79,21 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector, !drm_dp_read_lttpr_common_caps(aux, dpcd, outp->dp.lttpr.caps)) { int nr = drm_dp_lttpr_count(outp->dp.lttpr.caps); - if (nr > 0) - outp->dp.lttpr.nr = nr; + if (nr) { + drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE, + DP_PHY_REPEATER_MODE_TRANSPARENT); + + if (nr > 0) { + ret = drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE, + DP_PHY_REPEATER_MODE_NON_TRANSPARENT); + if (ret != 1) { + drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE, + DP_PHY_REPEATER_MODE_TRANSPARENT); + } else { + outp->dp.lttpr.nr = nr; + } + } + } } ret = drm_dp_read_dpcd_caps(aux, dpcd); @@ -291,23 +304,71 @@ nouveau_dp_power_down(struct nouveau_encoder *outp) int ret; u8 pwr; + mutex_lock(&outp->dp.hpd_irq_lock); + ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr); if (ret == 1) { pwr &= ~DP_SET_POWER_MASK; pwr |= DP_SET_POWER_D3; drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); } + + outp->dp.lt.nr = 0; + mutex_unlock(&outp->dp.hpd_irq_lock); +} + +static bool +nouveau_dp_train_link(struct nouveau_encoder *outp, bool retrain) +{ + int ret; + + ret = nvif_outp_dp_train(&outp->outp, outp->dp.dpcd, + outp->dp.lttpr.nr, + outp->dp.lt.nr, + outp->dp.lt.bw, + outp->dp.lt.mst, + false, + retrain); + + return ret == 0; } bool -nouveau_dp_link_check(struct nouveau_connector *nv_connector) +nouveau_dp_train(struct nouveau_encoder *outp, bool mst, u32 khz, u8 bpc) { - struct nouveau_encoder *nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); + bool ret; - if (!nv_encoder || nv_encoder->outp.or.id < 0) - return true; + mutex_lock(&outp->dp.hpd_irq_lock); + + outp->dp.lt.nr = outp->dp.link_nr; + outp->dp.lt.bw = 0; + outp->dp.lt.mst = mst; + ret = nouveau_dp_train_link(outp, false); + + mutex_unlock(&outp->dp.hpd_irq_lock); + return ret; +} + +static bool +nouveau_dp_link_check_locked(struct nouveau_encoder *outp) +{ + return nouveau_dp_train_link(outp, true); +} + +bool +nouveau_dp_link_check(struct nouveau_connector *nv_connector) +{ + struct nouveau_encoder *outp = nv_connector->dp_encoder; + bool link_ok = true; + + if (outp) { + mutex_lock(&outp->dp.hpd_irq_lock); + if (outp->dp.lt.nr) + link_ok = nouveau_dp_link_check_locked(outp); + mutex_unlock(&outp->dp.hpd_irq_lock); + } - return nvif_outp_dp_retrain(&nv_encoder->outp) == 0; + return link_ok; } void diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index ed31db58176c3..333042fc493fa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -89,6 +89,12 @@ struct nouveau_encoder { int link_nr; int link_bw; + struct { + bool mst; + u8 nr; + u32 bw; + } lt; + /* Protects DP state that needs to be accessed outside * connector reprobing contexts */ @@ -155,6 +161,7 @@ enum nouveau_dp_status { }; int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *); +bool nouveau_dp_train(struct nouveau_encoder *, bool mst, u32 khz, u8 bpc); void nouveau_dp_power_down(struct nouveau_encoder *); bool nouveau_dp_link_check(struct nouveau_connector *); void nouveau_dp_irq(struct work_struct *); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 050d5cd303ad4..7ffd57d82f89f 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -47,32 +47,26 @@ nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head, } int -nvif_outp_dp_retrain(struct nvif_outp *outp) +nvif_outp_dp_train(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 lttprs, + u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, bool retrain) { - int ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RETRAIN, NULL, 0); - NVIF_ERRON(ret, &outp->object, "[DP_RETRAIN]"); - return ret; -} - -static inline int nvif_outp_acquire(struct nvif_outp *, u8, struct nvif_outp_acquire_v0 *); - -int -nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], - int link_nr, int link_bw, bool hda, bool mst) -{ - struct nvif_outp_acquire_v0 args; + struct nvif_outp_dp_train_v0 args; int ret; - args.dp.link_nr = link_nr; - args.dp.link_bw = link_bw; - args.dp.hda = hda; - args.dp.mst = mst; - memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd)); - - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args); + args.version = 0; + args.retrain = retrain; + args.mst = mst; + args.lttprs = lttprs; + args.post_lt_adj = post_lt_adj; + args.link_nr = link_nr; + args.link_bw = link_bw; + memcpy(args.dpcd, dpcd, sizeof(args.dpcd)); + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_TRAIN, &args, sizeof(args)); NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d", - args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link); + "[DP_TRAIN retrain:%d mst:%d lttprs:%d post_lt_adj:%d nr:%d bw:%d]", + args.retrain, args.mst, args.lttprs, args.post_lt_adj, args.link_nr, + args.link_bw); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index af0f81a2834b6..b59cd2d4550f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -303,26 +303,13 @@ 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; @@ -467,6 +454,19 @@ nvkm_dp_train_init(struct nvkm_outp *outp) } } +static int +nvkm_dp_train_(struct nvkm_outp *outp, bool retrain) +{ + if (retrain) { + if (!atomic_read(&outp->dp.lt.done)) + return 0; + + return outp->func->acquire(outp); + } + + return 0; +} + static int nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) { @@ -501,19 +501,6 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) 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++) { @@ -615,50 +602,6 @@ nvkm_dp_acquire(struct nvkm_outp *outp) return ret; } -/* 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; -} - void nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) { @@ -690,36 +633,6 @@ 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)) { - 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]); - } } else if (!auxpwr && outp->dp.aux_pwr) { OUTP_DBG(outp, "aux power -> demand"); @@ -771,6 +684,7 @@ nvkm_dp_func = { .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_, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 5cef5933e7f25..5ac4cf596bc39 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -58,6 +58,7 @@ struct nvkm_outp { u8 nr; u8 bw; bool mst; + bool post_adj; } lt; } dp; }; @@ -109,6 +110,7 @@ struct nvkm_outp_func { 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); } dp; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index fd756e4599dab..16a1536d13aaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -46,28 +46,26 @@ 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_train(struct nvkm_outp *outp, void *argv, u32 argc) { - union nvif_outp_dp_retrain_args *args = argv; + union nvif_outp_dp_train_args *args = argv; - if (argc != sizeof(args->vn)) + if (argc != sizeof(args->v0) || args->v0.version != 0) return -ENOSYS; + if (!outp->func->dp.train) + return -EINVAL; - if (!atomic_read(&outp->dp.lt.done)) - return 0; - - return outp->func->acquire(outp); -} + if (!args->v0.retrain) { + memcpy(outp->dp.dpcd, args->v0.dpcd, sizeof(outp->dp.dpcd)); + outp->dp.lttprs = args->v0.lttprs; + outp->dp.links = args->v0.link_nr; + outp->dp.lt.nr = 0; + outp->dp.lt.bw = 0; + outp->dp.lt.mst = args->v0.mst; + outp->dp.lt.post_adj = args->v0.post_lt_adj; + } -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) -{ - 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; - return 0; + return outp->func->dp.train(outp, args->v0.retrain); } static int @@ -304,13 +302,6 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) case NVIF_OUTP_ACQUIRE_V0_SOR: ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda); 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); - break; default: ret = -EINVAL; break; @@ -458,7 +449,7 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc); + case NVIF_OUTP_V0_DP_TRAIN : return nvkm_uoutp_mthd_dp_train (outp, argv, argc); case NVIF_OUTP_V0_DP_MST_VCPI : return nvkm_uoutp_mthd_dp_mst_vcpi (outp, argv, argc); default: break; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 33/44] drm/nouveau/disp: move link training out of supervisor
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 11 ++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 1 + drivers/gpu/drm/nouveau/nouveau_dp.c | 122 ++++++++++++++- drivers/gpu/drm/nouveau/nvif/outp.c | 16 ++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 148 +++++------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 13 -- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 18 ++- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 8 +- .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 27 +++- 9 files changed, 218 insertions(+), 146 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 14972b942be7e..00ce0a46c152b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -35,6 +35,7 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DP_AUX_XFER 0x71 #define NVIF_OUTP_V0_DP_RATES 0x72 #define NVIF_OUTP_V0_DP_TRAIN 0x73 +#define NVIF_OUTP_V0_DP_DRIVE 0x74 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 union nvif_outp_detect_args { @@ -211,6 +212,16 @@ union nvif_outp_dp_train_args { } v0; }; +union nvif_outp_dp_drive_args { + struct nvif_outp_dp_drive_v0 { + __u8 version; + __u8 pad01[2]; + __u8 lanes; + __u8 pe[4]; + __u8 vs[4]; + } v0; +}; + union nvif_outp_dp_mst_vcpi_args { struct nvif_outp_dp_mst_vcpi_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 9a78483e0289d..b4f97fabecbdc 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -67,6 +67,7 @@ int nvif_outp_dp_rates(struct nvif_outp *, struct nvif_outp_dp_rate *rate, int r int nvif_outp_dp_train(struct nvif_outp *, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 lttprs, u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, bool retrain); +int nvif_outp_dp_drive(struct nvif_outp *, u8 link_nr, u8 pe[4], u8 vs[4]); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 9280daf325341..7de7707ec6a89 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -320,15 +320,83 @@ nouveau_dp_power_down(struct nouveau_encoder *outp) static bool nouveau_dp_train_link(struct nouveau_encoder *outp, bool retrain) { - int ret; + struct drm_dp_aux *aux = &outp->conn->aux; + bool post_lt = false; + int ret, retries = 0; + + if ( (outp->dp.dpcd[DP_MAX_LANE_COUNT] & 0x20) && + !(outp->dp.dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED)) + post_lt = true; +retry: ret = nvif_outp_dp_train(&outp->outp, outp->dp.dpcd, outp->dp.lttpr.nr, outp->dp.lt.nr, outp->dp.lt.bw, outp->dp.lt.mst, - false, + post_lt, retrain); + if (ret) + return false; + + if (post_lt) { + u8 stat[DP_LINK_STATUS_SIZE]; + u8 prev[2]; + u8 time = 0, adjusts = 0, tmp; + + ret = drm_dp_dpcd_read_phy_link_status(aux, DP_PHY_DPRX, stat); + if (ret) + return false; + + for (;;) { + if (!drm_dp_channel_eq_ok(stat, outp->dp.lt.nr)) { + ret = 1; + break; + } + + if (!(stat[2] & 0x02)) + break; + + msleep(5); + time += 5; + + memcpy(prev, &stat[4], sizeof(prev)); + ret = drm_dp_dpcd_read_phy_link_status(aux, DP_PHY_DPRX, stat); + if (ret) + break; + + if (!memcmp(prev, &stat[4], sizeof(prev))) { + if (time > 200) + break; + } else { + u8 pe[4], vs[4]; + + if (adjusts++ == 6) + break; + + for (int i = 0; i < outp->dp.lt.nr; i++) { + pe[i] = drm_dp_get_adjust_request_pre_emphasis(stat, i) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + vs[i] = drm_dp_get_adjust_request_voltage(stat, i) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + } + + ret = nvif_outp_dp_drive(&outp->outp, outp->dp.lt.nr, pe, vs); + if (ret) + break; + + time = 0; + } + } + + if (drm_dp_dpcd_readb(aux, DP_LANE_COUNT_SET, &tmp) == 1) { + tmp &= ~0x20; + drm_dp_dpcd_writeb(aux, DP_LANE_COUNT_SET, tmp); + } + } + + if (ret == 1 && retries++ < 3) + goto retry; return ret == 0; } @@ -336,15 +404,44 @@ nouveau_dp_train_link(struct nouveau_encoder *outp, bool retrain) bool nouveau_dp_train(struct nouveau_encoder *outp, bool mst, u32 khz, u8 bpc) { - bool ret; + struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev); + struct drm_dp_aux *aux = &outp->conn->aux; + u32 min_rate; + u8 pwr; + bool ret = true; + + if (mst) + min_rate = outp->dp.link_nr * outp->dp.rate[0].rate; + else + min_rate = DIV_ROUND_UP(khz * bpc * 3, 8); + + NV_DEBUG(drm, "%s link training (mst:%d min_rate:%d)\n", + outp->base.base.name, mst, min_rate); mutex_lock(&outp->dp.hpd_irq_lock); - outp->dp.lt.nr = outp->dp.link_nr; - outp->dp.lt.bw = 0; - outp->dp.lt.mst = mst; - ret = nouveau_dp_train_link(outp, false); + if (drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr) == 1) { + if ((pwr & DP_SET_POWER_MASK) != DP_SET_POWER_D0) { + pwr &= ~DP_SET_POWER_MASK; + pwr |= DP_SET_POWER_D0; + drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); + } + } + + for (int nr = outp->dp.link_nr; nr; nr >>= 1) { + for (int rate = 0; rate < outp->dp.rate_nr; rate++) { + if (outp->dp.rate[rate].rate * nr >= min_rate) { + outp->dp.lt.nr = nr; + outp->dp.lt.bw = outp->dp.rate[rate].rate; + outp->dp.lt.mst = mst; + if (nouveau_dp_train_link(outp, false)) + goto done; + } + } + } + ret = false; +done: mutex_unlock(&outp->dp.hpd_irq_lock); return ret; } @@ -352,6 +449,17 @@ nouveau_dp_train(struct nouveau_encoder *outp, bool mst, u32 khz, u8 bpc) static bool nouveau_dp_link_check_locked(struct nouveau_encoder *outp) { + u8 link_status[DP_LINK_STATUS_SIZE]; + + if (!outp || !outp->dp.lt.nr) + return true; + + if (drm_dp_dpcd_read_phy_link_status(&outp->conn->aux, DP_PHY_DPRX, link_status) < 0) + return false; + + if (drm_dp_channel_eq_ok(link_status, outp->dp.lt.nr)) + return true; + return nouveau_dp_train_link(outp, true); } diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 7ffd57d82f89f..5fe5523587e6a 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -46,6 +46,22 @@ nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head, return ret; } +int +nvif_outp_dp_drive(struct nvif_outp *outp, u8 link_nr, u8 pe[4], u8 vs[4]) +{ + struct nvif_outp_dp_drive_v0 args; + int ret; + + args.version = 0; + args.lanes = link_nr; + memcpy(args.pe, pe, sizeof(args.pe)); + memcpy(args.vs, vs, sizeof(args.vs)); + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_DRIVE, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_DRIVE lanes:%d]", args.lanes); + return ret; +} + int nvif_outp_dp_train(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 lttprs, u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, bool retrain) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index b59cd2d4550f5..77a91d42b977a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -315,6 +315,8 @@ nvkm_dp_train_link(struct nvkm_outp *outp, int rate) 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) @@ -455,71 +457,58 @@ nvkm_dp_train_init(struct nvkm_outp *outp) } static int -nvkm_dp_train_(struct nvkm_outp *outp, bool retrain) +nvkm_dp_drive(struct nvkm_outp *outp, u8 lanes, u8 pe[4], u8 vs[4]) { - if (retrain) { - if (!atomic_read(&outp->dp.lt.done)) - return 0; - - return outp->func->acquire(outp); - } + 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 0; + return nvkm_dp_train_drive(<, false); } static int -nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) +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); - - /* 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; } @@ -537,69 +526,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; - } - } + nvkm_dp_disable(outp, outp->ior); - 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; + nvkm_outp_release(outp); } void @@ -638,7 +568,6 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) 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. @@ -677,14 +606,14 @@ nvkm_dp_func = { .fini = nvkm_dp_fini, .detect = nvkm_outp_detect, .inherit = nvkm_outp_inherit, - .acquire = nvkm_dp_acquire, + .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.train = nvkm_dp_train, + .dp.drive = nvkm_dp_drive, }; int @@ -723,6 +652,5 @@ 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); mutex_init(&outp->dp.mutex); - atomic_set(&outp->dp.lt.done, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 948a46f3a1bdf..e9d0a9b715d47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1286,10 +1286,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); @@ -1319,7 +1315,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. */ @@ -1330,14 +1325,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 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 28ec7b3785130..f1a3e623bb222 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -31,7 +31,7 @@ #include <subdev/gpio.h> #include <subdev/i2c.h> -void +static void nvkm_outp_route(struct nvkm_disp *disp) { struct nvkm_outp *outp; @@ -96,8 +96,6 @@ nvkm_outp_release_or(struct nvkm_outp *outp, u8 user) 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; } @@ -277,6 +275,18 @@ nvkm_outp_release(struct nvkm_outp *outp) nvkm_outp_route(outp->disp); } +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; +} + void nvkm_outp_fini(struct nvkm_outp *outp) { @@ -412,6 +422,8 @@ static const struct nvkm_outp_func nvkm_outp = { .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, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 5ac4cf596bc39..cda17941de89a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -50,11 +50,9 @@ struct nvkm_outp { u32 rate; } rate[8]; int rates; - int links; struct mutex mutex; struct { - atomic_t done; u8 nr; u8 bw; bool mst; @@ -79,11 +77,11 @@ void nvkm_outp_fini(struct nvkm_outp *); 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); -void nvkm_outp_route(struct nvkm_disp *); int nvkm_outp_bl_get(struct nvkm_outp *); int nvkm_outp_bl_set(struct nvkm_outp *, int level); @@ -97,9 +95,8 @@ struct nvkm_outp_func { int (*edid_get)(struct nvkm_outp *, u8 *data, u16 *size); struct nvkm_ior *(*inherit)(struct nvkm_outp *); - int (*acquire)(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 *); @@ -111,6 +108,7 @@ struct nvkm_outp_func { 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]); } dp; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 16a1536d13aaf..b634e76c2a9ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -45,6 +45,19 @@ nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc) return 0; } +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) { @@ -58,9 +71,8 @@ nvkm_uoutp_mthd_dp_train(struct nvkm_outp *outp, void *argv, u32 argc) if (!args->v0.retrain) { memcpy(outp->dp.dpcd, args->v0.dpcd, sizeof(outp->dp.dpcd)); outp->dp.lttprs = args->v0.lttprs; - outp->dp.links = args->v0.link_nr; - outp->dp.lt.nr = 0; - outp->dp.lt.bw = 0; + 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; } @@ -279,7 +291,7 @@ nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) if (!outp->ior) return -EINVAL; - nvkm_outp_release(outp); + outp->func->release(outp); return 0; } @@ -297,10 +309,10 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) switch (args->v0.type) { case NVIF_OUTP_ACQUIRE_V0_DAC: case NVIF_OUTP_ACQUIRE_V0_PIOR: - ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, false); + ret = outp->func->acquire(outp, false); break; case NVIF_OUTP_ACQUIRE_V0_SOR: - ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda); + ret = outp->func->acquire(outp, args->v0.sor.hda); break; default: ret = -EINVAL; @@ -310,8 +322,6 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) if (ret) return ret; - nvkm_outp_route(outp->disp); - args->v0.or = outp->ior->id; args->v0.link = outp->ior->asy.link; return 0; @@ -450,6 +460,7 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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_MST_VCPI : return nvkm_uoutp_mthd_dp_mst_vcpi (outp, argv, argc); default: break; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 34/44] drm/nouveau/disp: add dp sst config method
From: Ben Skeggs <bskeggs at redhat.com> This is presently unused on HW, we read a bunch of regs and calculate the watermark during the second supervisor interrupt. I don't want to change this yet as I need to re-remember how older HW works exactly, but RM wants this info via RPC. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 12 +++++++++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 1 + drivers/gpu/drm/nouveau/nvif/outp.c | 18 ++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 2 ++ .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 21 +++++++++++++++++++ 5 files changed, 54 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 00ce0a46c152b..6fb297b65ae87 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -36,6 +36,7 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DP_RATES 0x72 #define NVIF_OUTP_V0_DP_TRAIN 0x73 #define NVIF_OUTP_V0_DP_DRIVE 0x74 +#define NVIF_OUTP_V0_DP_SST 0x75 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 union nvif_outp_detect_args { @@ -222,6 +223,17 @@ union nvif_outp_dp_drive_args { } v0; }; +union nvif_outp_dp_sst_args { + struct nvif_outp_dp_sst_v0 { + __u8 version; + __u8 head; + __u8 pad02[2]; + __u32 watermark; + __u32 hblanksym; + __u32 vblanksym; + } v0; +}; + union nvif_outp_dp_mst_vcpi_args { struct nvif_outp_dp_mst_vcpi_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index b4f97fabecbdc..881cbed5f0ee3 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -68,6 +68,7 @@ int nvif_outp_dp_train(struct nvif_outp *, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 lttprs, u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, bool retrain); int nvif_outp_dp_drive(struct nvif_outp *, u8 link_nr, u8 pe[4], u8 vs[4]); +int nvif_outp_dp_sst(struct nvif_outp *, int head, u32 watermark, u32 hblanksym, u32 vblanksym); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); #endif diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 5fe5523587e6a..952103aa93b78 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -46,6 +46,24 @@ nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head, return ret; } +int +nvif_outp_dp_sst(struct nvif_outp *outp, int head, u32 watermark, u32 hblanksym, u32 vblanksym) +{ + struct nvif_outp_dp_sst_v0 args; + int ret; + + args.version = 0; + args.head = head; + args.watermark = watermark; + args.hblanksym = hblanksym; + args.vblanksym = vblanksym; + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_SST, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, + "[DP_SST head:%d watermark:%d hblanksym:%d vblanksym:%d]", + args.head, args.watermark, args.hblanksym, args.vblanksym); + return ret; +} + int nvif_outp_dp_drive(struct nvif_outp *outp, u8 link_nr, u8 pe[4], u8 vs[4]) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 8686e5c044a5d..9beb9d1e86334 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -84,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); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index b634e76c2a9ba..225f88fbdae0f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -45,6 +45,26 @@ nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc) return 0; } +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 (!ior->func->dp || !nvkm_head_find(disp, args->v0.head)) + return -EINVAL; + if (!ior->func->dp->sst) + return 0; + + 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) { @@ -461,6 +481,7 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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_VCPI : return nvkm_uoutp_mthd_dp_mst_vcpi (outp, argv, argc); default: break; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 35/44] drm/nouveau/disp: add dp mst id get/put methods
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 32 ++++++++++++++++--- drivers/gpu/drm/nouveau/dispnv50/head.h | 1 + drivers/gpu/drm/nouveau/dispnv50/headc57d.c | 14 ++++++++ drivers/gpu/drm/nouveau/include/nvif/if0012.h | 18 +++++++++++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 2 ++ drivers/gpu/drm/nouveau/nvif/outp.c | 29 +++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 15 +++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 ++ .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 28 ++++++++++++++++ 9 files changed, 137 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index d8ed23ddd2e4c..d6de5ee89d543 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -869,6 +869,8 @@ struct nv50_msto { struct nv50_mstc *mstc; bool disabled; bool enabled; + + u32 display_id; }; struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) @@ -897,10 +899,17 @@ nv50_msto_cleanup(struct drm_atomic_state *state, drm_atomic_get_old_mst_topology_state(state, mgr); const struct drm_dp_mst_atomic_payload *old_payload drm_atomic_get_mst_payload_state(old_mst_state, msto->mstc->port); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); if (msto->disabled) { + if (msto->head->func->display_id) { + nvif_outp_dp_mst_id_put(&mstm->outp->outp, msto->display_id); + msto->display_id = 0; + } + msto->mstc = NULL; msto->disabled = false; drm_dp_remove_payload_part2(mgr, new_mst_state, old_payload, new_payload); @@ -1041,6 +1050,11 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st nouveau_dp_train(mstm->outp, true, 0, 0); } + if (head->func->display_id) { + if (!WARN_ON(nvif_outp_dp_mst_id_get(&mstm->outp->outp, &msto->display_id))) + head->func->display_id(head, msto->display_id); + } + if (mstm->outp->outp.or.link & 1) proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_A; else @@ -1061,6 +1075,9 @@ nv50_msto_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; + if (msto->head->func->display_id) + msto->head->func->display_id(msto->head, 0); + mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); mstm->modified = true; if (!--mstm->links) @@ -1544,7 +1561,7 @@ static void nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); + struct nv50_head *head = nv50_head(nv_encoder->crtc); struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder); #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); @@ -1563,7 +1580,7 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st #endif if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && nv_encoder->hdmi.enabled) { - nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, + nvif_outp_hdmi(&nv_encoder->outp, head->base.index, false, 0, 0, 0, false, false, false); nv_encoder->hdmi.enabled = false; } @@ -1571,8 +1588,11 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st if (nv_encoder->dcb->type == DCB_OUTPUT_DP) nouveau_dp_power_down(nv_encoder); - nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); - nv50_audio_disable(encoder, nv_crtc); + if (head->func->display_id) + head->func->display_id(head, 0); + + nv_encoder->update(nv_encoder, head->base.index, NULL, 0, 0); + nv50_audio_disable(encoder, &head->base); nv_encoder->crtc = NULL; } @@ -1585,6 +1605,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base)); struct drm_display_mode *mode = &asyh->state.adjusted_mode; struct nv50_disp *disp = nv50_disp(encoder->dev); + struct nv50_head *head = nv50_head(&nv_crtc->base); struct nvif_outp *outp = &nv_encoder->outp; struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); @@ -1682,6 +1703,9 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta break; } + if (head->func->display_id) + head->func->display_id(head, BIT(nv_encoder->dcb->id)); + nv_encoder->update(nv_encoder, nv_crtc->index, asyh, proto, depth); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h index 41c8788dfb312..e9d17037ffcfc 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.h +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h @@ -49,6 +49,7 @@ struct nv50_head_func { int (*procamp)(struct nv50_head *, struct nv50_head_atom *); int (*or)(struct nv50_head *, struct nv50_head_atom *); void (*static_wndw_map)(struct nv50_head *, struct nv50_head_atom *); + int (*display_id)(struct nv50_head *, u32 display_id); }; extern const struct nv50_head_func head507d; diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c index 543f08ceaad6d..53b1248c40ec8 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c @@ -27,6 +27,19 @@ #include <nvhw/class/clc57d.h> +static int +headc57d_display_id(struct nv50_head *head, u32 display_id) +{ + struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; + int ret; + + if ((ret = PUSH_WAIT(push, 2))) + return ret; + + PUSH_NVSQ(push, NVC57D, 0x2020 + (head->base.index * 0x400), display_id); + return 0; +} + static int headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh) { @@ -250,4 +263,5 @@ headc57d = { .or = headc57d_or, /* TODO: flexible window mappings */ .static_wndw_map = headc37d_static_wndw_map, + .display_id = headc57d_display_id, }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 6fb297b65ae87..502f342e0d775 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -37,6 +37,8 @@ union nvif_outp_args { #define NVIF_OUTP_V0_DP_TRAIN 0x73 #define NVIF_OUTP_V0_DP_DRIVE 0x74 #define NVIF_OUTP_V0_DP_SST 0x75 +#define NVIF_OUTP_V0_DP_MST_ID_GET 0x76 +#define NVIF_OUTP_V0_DP_MST_ID_PUT 0x77 #define NVIF_OUTP_V0_DP_MST_VCPI 0x78 union nvif_outp_detect_args { @@ -234,6 +236,22 @@ union nvif_outp_dp_sst_args { } v0; }; +union nvif_outp_dp_mst_id_put_args { + struct nvif_outp_dp_mst_id_put_v0 { + __u8 version; + __u8 pad01[3]; + __u32 id; + } v0; +}; + +union nvif_outp_dp_mst_id_get_args { + struct nvif_outp_dp_mst_id_get_v0 { + __u8 version; + __u8 pad01[3]; + __u32 id; + } v0; +}; + union nvif_outp_dp_mst_vcpi_args { struct nvif_outp_dp_mst_vcpi_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 881cbed5f0ee3..2d86838ed5598 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -69,6 +69,8 @@ int nvif_outp_dp_train(struct nvif_outp *, u8 dpcd[DP_RECEIVER_CAP_SIZE], bool retrain); int nvif_outp_dp_drive(struct nvif_outp *, u8 link_nr, u8 pe[4], u8 vs[4]); int nvif_outp_dp_sst(struct nvif_outp *, int head, u32 watermark, u32 hblanksym, u32 vblanksym); +int nvif_outp_dp_mst_id_get(struct nvif_outp *, u32 *id); +int nvif_outp_dp_mst_id_put(struct nvif_outp *, u32 id); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); #endif diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 952103aa93b78..97e5855c2cf54 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -46,6 +46,35 @@ nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head, return ret; } +int +nvif_outp_dp_mst_id_put(struct nvif_outp *outp, u32 id) +{ + struct nvif_outp_dp_mst_id_get_v0 args; + int ret; + + args.version = 0; + args.id = id; + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_ID_PUT, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_MST_ID_PUT id:%08x]", args.id); + return ret; +} + +int +nvif_outp_dp_mst_id_get(struct nvif_outp *outp, u32 *id) +{ + struct nvif_outp_dp_mst_id_get_v0 args; + int ret; + + args.version = 0; + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_ID_GET, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_MST_ID_GET] id:%08x", args.id); + if (ret) + return ret; + + *id = args.id; + return 0; +} + int nvif_outp_dp_sst(struct nvif_outp *outp, int head, u32 watermark, u32 hblanksym, u32 vblanksym) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 77a91d42b977a..aaa7796946ceb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -41,6 +41,19 @@ */ #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) { @@ -614,6 +627,8 @@ nvkm_dp_func = { .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 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index cda17941de89a..3ec7318d9144e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -109,6 +109,8 @@ struct nvkm_outp_func { 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; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 225f88fbdae0f..ad52d9ed594af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -45,6 +45,32 @@ nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc) return 0; } +static int +nvkm_uoutp_mthd_dp_mst_id_put(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_mst_id_put_args *args = argv; + + 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) { @@ -482,6 +508,8 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 36/44] drm/nouveau/disp: move outp/conn construction to chipset code
From: Ben Skeggs <bskeggs at redhat.com> - pre-nv5x doesn't use any of this, has its own version DRM-side - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 117 +---------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 122 +++++++++++++++++- 2 files changed, 121 insertions(+), 118 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 73104b59f97fe..1dbe68f9a0e07 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> @@ -159,123 +156,11 @@ 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_outp *outp; 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) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index e9d0a9b715d47..7343b24f10eb7 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" @@ -1581,7 +1583,14 @@ 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; 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); @@ -1628,8 +1637,117 @@ 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_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); + } + + /* 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); + } + + return 0; } static const struct nvkm_disp_func -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 37/44] drm/nouveau/disp: move outp init/fini paths to chipset code
From: Ben Skeggs <bskeggs at redhat.com> - pre-nv5x doesn't use any of this - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 31 +++---------------- .../gpu/drm/nouveau/nvkm/engine/disp/conn.c | 10 ------ .../gpu/drm/nouveau/nvkm/engine/disp/conn.h | 2 -- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 14 +++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 20 ++---------- 6 files changed, 22 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 1dbe68f9a0e07..39f7e7ce9f4a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -102,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); 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; @@ -123,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) { @@ -156,9 +148,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_subdev *subdev = &disp->engine.subdev; - struct nvkm_outp *outp; struct nvkm_head *head; - struct nvkm_ior *ior; int ret, i; if (disp->func->oneinit) { @@ -167,19 +157,6 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) 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); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index fbdae11378646..ff88a5a5253a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -29,16 +29,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) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index a0600e72b0ecd..01c3146c7066f 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 aaa7796946ceb..b35fae96d855d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -603,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); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 7343b24f10eb7..4be09ec4fd5c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1586,6 +1586,7 @@ nv50_disp_oneinit(struct nvkm_disp *disp) 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; @@ -1747,6 +1748,19 @@ nv50_disp_oneinit(struct nvkm_disp *disp) 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; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index f1a3e623bb222..bfb2a4db8d644 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -287,13 +287,6 @@ nvkm_outp_acquire(struct nvkm_outp *outp, bool hda) return 0; } -void -nvkm_outp_fini(struct nvkm_outp *outp) -{ - if (outp->func->fini) - outp->func->fini(outp); -} - struct nvkm_ior * nvkm_outp_inherit(struct nvkm_outp *outp) { @@ -332,8 +325,8 @@ nvkm_outp_inherit(struct nvkm_outp *outp) return ior; } -static void -nvkm_outp_init_route(struct nvkm_outp *outp) +void +nvkm_outp_init(struct nvkm_outp *outp) { enum nvkm_ior_proto proto; enum nvkm_ior_type type; @@ -365,14 +358,6 @@ nvkm_outp_init_route(struct nvkm_outp *outp) ior->arm.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) { @@ -420,6 +405,7 @@ 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, -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 38/44] drm/nouveau/disp/nv50-: skip DCB_OUTPUT_TV
From: Ben Skeggs <bskeggs at redhat.com> We've never supported it. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 4be09ec4fd5c2..2d05e2f7e46b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1656,7 +1656,6 @@ nv50_disp_oneinit(struct nvkm_disp *disp) 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); @@ -1664,6 +1663,7 @@ nv50_disp_oneinit(struct nvkm_disp *disp) 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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 39/44] drm/nouveau/kms/nv50-: create heads based on nvkm head mask
From: Ben Skeggs <bskeggs at redhat.com> No need to go poking HW directly, and probably shouldn't on GSP-RM. Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index d6de5ee89d543..2134502ec04e2 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2692,13 +2692,12 @@ nv50_display_destroy(struct drm_device *dev) int nv50_display_create(struct drm_device *dev) { - struct nvif_device *device = &nouveau_drm(dev)->client.device; struct nouveau_drm *drm = nouveau_drm(dev); struct dcb_table *dcb = &drm->vbios.dcb; struct drm_connector *connector, *tmp; struct nv50_disp *disp; struct dcb_output *dcbe; - int crtcs, ret, i; + int ret, i; bool has_mst = nv50_has_mst(drm); disp = kzalloc(sizeof(*disp), GFP_KERNEL); @@ -2776,20 +2775,9 @@ nv50_display_create(struct drm_device *dev) } /* create crtc objects to represent the hw heads */ - if (disp->disp->object.oclass >= GV100_DISP) - crtcs = nvif_rd32(&device->object, 0x610060) & 0xff; - else - if (disp->disp->object.oclass >= GF110_DISP) - crtcs = nvif_rd32(&device->object, 0x612004) & 0xf; - else - crtcs = 0x3; - - for (i = 0; i < fls(crtcs); i++) { + for_each_set_bit(i, &disp->disp->head_mask, sizeof(disp->disp->head_mask) * 8) { struct nv50_head *head; - if (!(crtcs & (1 << i))) - continue; - head = nv50_head_create(dev, i); if (IS_ERR(head)) { ret = PTR_ERR(head); @@ -2814,7 +2802,7 @@ nv50_display_create(struct drm_device *dev) * Once these issues are closed, this should be * removed */ - head->msto->encoder.possible_crtcs = crtcs; + head->msto->encoder.possible_crtcs = disp->disp->head_mask; } } -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 40/44] drm/nouveau/kms/nv50-: create heads after outps/conns
From: Ben Skeggs <bskeggs at redhat.com> - output info will be used later to determine MST support Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 64 ++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 2134502ec04e2..26d59346703e3 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2774,38 +2774,6 @@ nv50_display_create(struct drm_device *dev) dev->mode_config.cursor_height = 64; } - /* create crtc objects to represent the hw heads */ - for_each_set_bit(i, &disp->disp->head_mask, sizeof(disp->disp->head_mask) * 8) { - struct nv50_head *head; - - head = nv50_head_create(dev, i); - if (IS_ERR(head)) { - ret = PTR_ERR(head); - goto out; - } - - if (has_mst) { - head->msto = nv50_msto_new(dev, head, i); - if (IS_ERR(head->msto)) { - ret = PTR_ERR(head->msto); - head->msto = NULL; - goto out; - } - - /* - * FIXME: This is a hack to workaround the following - * issues: - * - * https://gitlab.gnome.org/GNOME/mutter/issues/759 - * https://gitlab.freedesktop.org/xorg/xserver/merge_requests/277 - * - * Once these issues are closed, this should be - * removed - */ - head->msto->encoder.possible_crtcs = disp->disp->head_mask; - } - } - /* create encoder/connector objects based on VBIOS DCB table */ for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { struct nouveau_encoder *outp; @@ -2868,6 +2836,38 @@ nv50_display_create(struct drm_device *dev) connector->funcs->destroy(connector); } + /* create crtc objects to represent the hw heads */ + for_each_set_bit(i, &disp->disp->head_mask, sizeof(disp->disp->head_mask) * 8) { + struct nv50_head *head; + + head = nv50_head_create(dev, i); + if (IS_ERR(head)) { + ret = PTR_ERR(head); + goto out; + } + + if (has_mst) { + head->msto = nv50_msto_new(dev, head, i); + if (IS_ERR(head->msto)) { + ret = PTR_ERR(head->msto); + head->msto = NULL; + goto out; + } + + /* + * FIXME: This is a hack to workaround the following + * issues: + * + * https://gitlab.gnome.org/GNOME/mutter/issues/759 + * https://gitlab.freedesktop.org/xorg/xserver/merge_requests/277 + * + * Once these issues are closed, this should be + * removed + */ + head->msto->encoder.possible_crtcs = disp->disp->head_mask; + } + } + /* Disable vblank irqs aggressively for power-saving, safe on nv50+ */ dev->vblank_disable_immediate = true; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 41/44] drm/nouveau/kms/nv50-: name aux channels after their connector
From: Ben Skeggs <bskeggs at redhat.com> - removes use of VBIOS data for naming - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nouveau_connector.c | 25 ++++++++------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 063cefe26be20..73657736ce838 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -400,10 +400,8 @@ nouveau_connector_destroy(struct drm_connector *connector) kfree(nv_connector->edid); drm_connector_unregister(connector); drm_connector_cleanup(connector); - if (nv_connector->aux.transfer) { + if (nv_connector->aux.transfer) drm_dp_cec_unregister_connector(&nv_connector->aux); - kfree(nv_connector->aux.name); - } nvif_conn_dtor(&nv_connector->conn); kfree(connector); } @@ -1280,13 +1278,11 @@ struct drm_connector * nouveau_connector_create(struct drm_device *dev, const struct dcb_output *dcbe) { - const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - char aux_name[48] = {0}; int index = dcbe->connector; int type, ret = 0; bool dummy; @@ -1376,7 +1372,13 @@ nouveau_connector_create(struct drm_device *dev, } } - switch ((type = drm_conntype_from_dcb(nv_connector->type))) { + type = drm_conntype_from_dcb(nv_connector->type); + if (type == DRM_MODE_CONNECTOR_LVDS) + drm_connector_init(dev, connector, &nouveau_connector_funcs_lvds, type); + else + drm_connector_init(dev, connector, &nouveau_connector_funcs, type); + + switch (type) { case DRM_MODE_CONNECTOR_LVDS: ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy); if (ret) { @@ -1385,24 +1387,16 @@ nouveau_connector_create(struct drm_device *dev, return ERR_PTR(ret); } - funcs = &nouveau_connector_funcs_lvds; break; case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: nv_connector->aux.dev = connector->kdev; nv_connector->aux.drm_dev = dev; nv_connector->aux.transfer = nouveau_connector_aux_xfer; - snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x", - dcbe->hasht, dcbe->hashm); - nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL); - if (!nv_connector->aux.name) { - kfree(nv_connector); - return ERR_PTR(-ENOMEM); - } + nv_connector->aux.name = connector->name; drm_dp_aux_init(&nv_connector->aux); break; default: - funcs = &nouveau_connector_funcs; break; } @@ -1417,7 +1411,6 @@ nouveau_connector_create(struct drm_device *dev, connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_connector_init(dev, connector, funcs, type); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_CONNECT; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 42/44] drm/nouveau/kms/nv50-: create connectors based on nvkm info
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv04/disp.c | 2 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/nouveau/include/nvif/conn.h | 15 ++ drivers/gpu/drm/nouveau/include/nvif/if0011.h | 10 ++ drivers/gpu/drm/nouveau/nouveau_connector.c | 131 +++++++++--------- drivers/gpu/drm/nouveau/nouveau_connector.h | 3 +- drivers/gpu/drm/nouveau/nvif/conn.c | 22 ++- .../gpu/drm/nouveau/nvkm/engine/disp/uconn.c | 26 ++++ 8 files changed, 139 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index e9ac3fb27ff78..13705c5f14973 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -256,7 +256,7 @@ nv04_display_create(struct drm_device *dev) for (i = 0; i < dcb->entries; i++) { struct dcb_output *dcbent = &dcb->entry[i]; - connector = nouveau_connector_create(dev, dcbent); + connector = nouveau_connector_create(dev, dcbent->connector); if (IS_ERR(connector)) continue; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 26d59346703e3..e2fa748e66f16 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2788,7 +2788,7 @@ nv50_display_create(struct drm_device *dev) continue; } - connector = nouveau_connector_create(dev, dcbe); + connector = nouveau_connector_create(dev, dcbe->connector); if (IS_ERR(connector)) { nvif_outp_dtor(&outp->outp); kfree(outp); diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h index 8a6017a358976..406c12a111f9d 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/conn.h +++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h @@ -7,6 +7,21 @@ struct nvif_disp; struct nvif_conn { struct nvif_object object; + u32 id; + + struct { + enum { + NVIF_CONN_VGA, + NVIF_CONN_TV, + NVIF_CONN_DVI_I, + NVIF_CONN_DVI_D, + NVIF_CONN_LVDS, + NVIF_CONN_LVDS_SPWG, + NVIF_CONN_HDMI, + NVIF_CONN_DP, + NVIF_CONN_EDP, + } type; + } info; }; int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h index 0c25288a5a789..3ed0ddd75bd8f 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h @@ -7,6 +7,16 @@ union nvif_conn_args { __u8 version; __u8 id; /* DCB connector table index. */ __u8 pad02[6]; +#define NVIF_CONN_V0_VGA 0x00 +#define NVIF_CONN_V0_TV 0x01 +#define NVIF_CONN_V0_DVI_I 0x02 +#define NVIF_CONN_V0_DVI_D 0x03 +#define NVIF_CONN_V0_LVDS 0x04 +#define NVIF_CONN_V0_LVDS_SPWG 0x05 +#define NVIF_CONN_V0_HDMI 0x06 +#define NVIF_CONN_V0_DP 0x07 +#define NVIF_CONN_V0_EDP 0x08 + __u8 type; } v0; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 73657736ce838..21cc8dfcb7add 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1275,15 +1275,13 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb) } struct drm_connector * -nouveau_connector_create(struct drm_device *dev, - const struct dcb_output *dcbe) +nouveau_connector_create(struct drm_device *dev, int index) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - int index = dcbe->connector; int type, ret = 0; bool dummy; @@ -1305,70 +1303,76 @@ nouveau_connector_create(struct drm_device *dev, nv_connector->index = index; INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq); - /* attempt to parse vbios connector type and hotplug gpio */ - nv_connector->dcb = olddcb_conn(dev, index); - if (nv_connector->dcb) { - u32 entry = ROM16(nv_connector->dcb[0]); - if (olddcb_conntab(dev)[3] >= 4) - entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; - - nv_connector->type = nv_connector->dcb[0]; - if (drm_conntype_from_dcb(nv_connector->type) =- DRM_MODE_CONNECTOR_Unknown) { - NV_WARN(drm, "unknown connector type %02x\n", - nv_connector->type); - nv_connector->type = DCB_CONNECTOR_NONE; + if (disp->disp.conn_mask & BIT(nv_connector->index)) { + ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, + &nv_connector->conn); + if (ret) { + kfree(nv_connector); + return ERR_PTR(ret); } - /* Gigabyte NX85T */ - if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) { - if (nv_connector->type == DCB_CONNECTOR_HDMI_1) - nv_connector->type = DCB_CONNECTOR_DVI_I; + switch (nv_connector->conn.info.type) { + case NVIF_CONN_VGA : type = DCB_CONNECTOR_VGA; break; + case NVIF_CONN_DVI_I : type = DCB_CONNECTOR_DVI_I; break; + case NVIF_CONN_DVI_D : type = DCB_CONNECTOR_DVI_D; break; + case NVIF_CONN_LVDS : type = DCB_CONNECTOR_LVDS; break; + case NVIF_CONN_LVDS_SPWG: type = DCB_CONNECTOR_LVDS_SPWG; break; + case NVIF_CONN_DP : type = DCB_CONNECTOR_DP; break; + case NVIF_CONN_EDP : type = DCB_CONNECTOR_eDP; break; + case NVIF_CONN_HDMI : type = DCB_CONNECTOR_HDMI_0; break; + default: + WARN_ON(1); + return NULL; } - /* Gigabyte GV-NX86T512H */ - if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) { - if (nv_connector->type == DCB_CONNECTOR_HDMI_1) - nv_connector->type = DCB_CONNECTOR_DVI_I; - } + nv_connector->type = type; } else { - nv_connector->type = DCB_CONNECTOR_NONE; - } + u8 *dcb = olddcb_conn(dev, nv_connector->index); - /* no vbios data, or an unknown dcb connector type - attempt to - * figure out something suitable ourselves - */ - if (nv_connector->type == DCB_CONNECTOR_NONE) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct dcb_table *dcbt = &drm->vbios.dcb; - u32 encoders = 0; - int i; - - for (i = 0; i < dcbt->entries; i++) { - if (dcbt->entry[i].connector == nv_connector->index) - encoders |= (1 << dcbt->entry[i].type); + if (dcb) + nv_connector->type = dcb[0]; + else + nv_connector->type = DCB_CONNECTOR_NONE; + + /* attempt to parse vbios connector type and hotplug gpio */ + if (nv_connector->type != DCB_CONNECTOR_NONE) { + if (drm_conntype_from_dcb(nv_connector->type) =+ DRM_MODE_CONNECTOR_Unknown) { + NV_WARN(drm, "unknown connector type %02x\n", + nv_connector->type); + nv_connector->type = DCB_CONNECTOR_NONE; + } } - if (encoders & (1 << DCB_OUTPUT_DP)) { - if (encoders & (1 << DCB_OUTPUT_TMDS)) - nv_connector->type = DCB_CONNECTOR_DP; - else - nv_connector->type = DCB_CONNECTOR_eDP; - } else - if (encoders & (1 << DCB_OUTPUT_TMDS)) { - if (encoders & (1 << DCB_OUTPUT_ANALOG)) - nv_connector->type = DCB_CONNECTOR_DVI_I; - else - nv_connector->type = DCB_CONNECTOR_DVI_D; - } else - if (encoders & (1 << DCB_OUTPUT_ANALOG)) { - nv_connector->type = DCB_CONNECTOR_VGA; - } else - if (encoders & (1 << DCB_OUTPUT_LVDS)) { - nv_connector->type = DCB_CONNECTOR_LVDS; - } else - if (encoders & (1 << DCB_OUTPUT_TV)) { - nv_connector->type = DCB_CONNECTOR_TV_0; + /* no vbios data, or an unknown dcb connector type - attempt to + * figure out something suitable ourselves + */ + if (nv_connector->type == DCB_CONNECTOR_NONE && + !WARN_ON(drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)) { + struct dcb_table *dcbt = &drm->vbios.dcb; + u32 encoders = 0; + int i; + + for (i = 0; i < dcbt->entries; i++) { + if (dcbt->entry[i].connector == nv_connector->index) + encoders |= (1 << dcbt->entry[i].type); + } + + if (encoders & (1 << DCB_OUTPUT_TMDS)) { + if (encoders & (1 << DCB_OUTPUT_ANALOG)) + nv_connector->type = DCB_CONNECTOR_DVI_I; + else + nv_connector->type = DCB_CONNECTOR_DVI_D; + } else + if (encoders & (1 << DCB_OUTPUT_ANALOG)) { + nv_connector->type = DCB_CONNECTOR_VGA; + } else + if (encoders & (1 << DCB_OUTPUT_LVDS)) { + nv_connector->type = DCB_CONNECTOR_LVDS; + } else + if (encoders & (1 << DCB_OUTPUT_TV)) { + nv_connector->type = DCB_CONNECTOR_TV_0; + } } } @@ -1414,14 +1418,7 @@ nouveau_connector_create(struct drm_device *dev, drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_CONNECT; - if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) { - ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, - &nv_connector->conn); - if (ret) { - kfree(nv_connector); - return ERR_PTR(ret); - } - + if (nvif_object_constructed(&nv_connector->conn.object)) { ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug", nouveau_connector_hotplug, NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG, diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 35bcb541722b8..a2df4918340cb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -121,7 +121,6 @@ struct nouveau_connector { struct drm_connector base; enum dcb_connector_type type; u8 index; - u8 *dcb; struct nvif_conn conn; u64 hpd_pending; @@ -200,7 +199,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) } struct drm_connector * -nouveau_connector_create(struct drm_device *, const struct dcb_output *); +nouveau_connector_create(struct drm_device *, int id); void nouveau_connector_hpd(struct nouveau_connector *, u64 bits); extern int nouveau_tv_disable; diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c index 879569d4ba4cc..9ee18cb992644 100644 --- a/drivers/gpu/drm/nouveau/nvif/conn.c +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -63,5 +63,25 @@ nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_con ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN, &args, sizeof(args), &conn->object); NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id); - return ret; + if (ret) + return ret; + + conn->id = id; + + switch (args.type) { + case NVIF_CONN_V0_VGA : conn->info.type = NVIF_CONN_VGA; break; + case NVIF_CONN_V0_TV : conn->info.type = NVIF_CONN_TV; break; + case NVIF_CONN_V0_DVI_I : conn->info.type = NVIF_CONN_DVI_I; break; + case NVIF_CONN_V0_DVI_D : conn->info.type = NVIF_CONN_DVI_D; break; + case NVIF_CONN_V0_LVDS : conn->info.type = NVIF_CONN_LVDS; break; + case NVIF_CONN_V0_LVDS_SPWG: conn->info.type = NVIF_CONN_LVDS_SPWG; break; + case NVIF_CONN_V0_HDMI : conn->info.type = NVIF_CONN_HDMI; break; + case NVIF_CONN_V0_DP : conn->info.type = NVIF_CONN_DP; break; + case NVIF_CONN_V0_EDP : conn->info.type = NVIF_CONN_EDP; break; + default: + break; + } + + return 0; + } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c index 971cccc0892cc..c6eeb8e44c15f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c @@ -142,6 +142,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; -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 43/44] drm/nouveau/kms/nv50-: create outputs based on nvkm info
From: Ben Skeggs <bskeggs at redhat.com> - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 97 ++++++++++--------- drivers/gpu/drm/nouveau/dispnv50/disp.h | 2 - drivers/gpu/drm/nouveau/include/nvif/if0012.h | 31 +++++- drivers/gpu/drm/nouveau/include/nvif/outp.h | 40 ++++++++ drivers/gpu/drm/nouveau/nouveau_connector.c | 2 +- drivers/gpu/drm/nouveau/nvif/outp.c | 44 +++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 50 ++++++++++ 9 files changed, 223 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index e2fa748e66f16..dcd19c4183894 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -66,8 +66,6 @@ #include "nouveau_fence.h" #include "nv50_display.h" -#include <subdev/bios/dp.h> - /****************************************************************************** * EVO channel *****************************************************************************/ @@ -1704,7 +1702,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta } if (head->func->display_id) - head->func->display_id(head, BIT(nv_encoder->dcb->id)); + head->func->display_id(head, BIT(nv_encoder->outp.id)); nv_encoder->update(nv_encoder, nv_crtc->index, asyh, proto, depth); } @@ -1736,16 +1734,6 @@ nv50_sor_func = { .destroy = nv50_sor_destroy, }; -bool nv50_has_mst(struct nouveau_drm *drm) -{ - struct nvkm_bios *bios = nvxx_bios(&drm->client.device); - u32 data; - u8 ver, hdr, cnt, len; - - data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len); - return data && ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 0x04); -} - static int nv50_sor_create(struct nouveau_encoder *nv_encoder) { @@ -1798,15 +1786,15 @@ nv50_sor_create(struct nouveau_encoder *nv_encoder) nv_encoder->i2c = &nv_connector->aux.ddc; } - if (nv_connector->type != DCB_CONNECTOR_eDP && - nv50_has_mst(drm)) { + if (nv_connector->type != DCB_CONNECTOR_eDP && nv_encoder->outp.info.dp.mst) { ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16, nv_connector->base.base.id, &nv_encoder->dp.mstm); if (ret) return ret; } - } else { + } else + if (nv_encoder->outp.info.ddc != NVIF_OUTP_DDC_INVALID) { struct nvkm_i2c_bus *bus nvkm_i2c_bus_find(i2c, dcbe->i2c_index); if (bus) @@ -1927,12 +1915,12 @@ nv50_pior_create(struct nouveau_encoder *nv_encoder) switch (dcbe->type) { case DCB_OUTPUT_TMDS: - bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev)); + bus = nvkm_i2c_bus_find(i2c, nv_encoder->outp.info.ddc); ddc = bus ? &bus->i2c : NULL; type = DRM_MODE_ENCODER_TMDS; break; case DCB_OUTPUT_DP: - aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev)); + aux = nvkm_i2c_aux_find(i2c, nv_encoder->outp.info.dp.aux); ddc = aux ? &aux->i2c : NULL; type = DRM_MODE_ENCODER_TMDS; break; @@ -2693,12 +2681,10 @@ int nv50_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct dcb_table *dcb = &drm->vbios.dcb; struct drm_connector *connector, *tmp; struct nv50_disp *disp; - struct dcb_output *dcbe; int ret, i; - bool has_mst = nv50_has_mst(drm); + bool has_mst = false; disp = kzalloc(sizeof(*disp), GFP_KERNEL); if (!disp) @@ -2775,54 +2761,75 @@ nv50_display_create(struct drm_device *dev) } /* create encoder/connector objects based on VBIOS DCB table */ - for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { + for_each_set_bit(i, &disp->disp->outp_mask, sizeof(disp->disp->outp_mask) * 8) { struct nouveau_encoder *outp; outp = kzalloc(sizeof(*outp), GFP_KERNEL); if (!outp) break; - ret = nvif_outp_ctor(disp->disp, "kmsOutp", dcbe->id, &outp->outp); + ret = nvif_outp_ctor(disp->disp, "kmsOutp", i, &outp->outp); if (ret) { kfree(outp); continue; } - connector = nouveau_connector_create(dev, dcbe->connector); + connector = nouveau_connector_create(dev, outp->outp.info.conn); if (IS_ERR(connector)) { nvif_outp_dtor(&outp->outp); kfree(outp); continue; } - outp->base.base.possible_crtcs = dcbe->heads; + outp->base.base.possible_crtcs = outp->outp.info.heads; outp->base.base.possible_clones = 0; - outp->dcb = dcbe; outp->conn = nouveau_connector(connector); - if (dcbe->location == DCB_LOC_ON_CHIP) { - switch (dcbe->type) { - case DCB_OUTPUT_TMDS: - case DCB_OUTPUT_LVDS: - case DCB_OUTPUT_DP: - ret = nv50_sor_create(outp); - break; - case DCB_OUTPUT_ANALOG: - ret = nv50_dac_create(outp); - break; - default: - ret = -ENODEV; - break; - } - } else { - ret = nv50_pior_create(outp); + outp->dcb = kzalloc(sizeof(*outp->dcb), GFP_KERNEL); + if (!outp->dcb) + break; + + switch (outp->outp.info.proto) { + case NVIF_OUTP_RGB_CRT: + outp->dcb->type = DCB_OUTPUT_ANALOG; + outp->dcb->crtconf.maxfreq = outp->outp.info.rgb_crt.freq_max; + break; + case NVIF_OUTP_TMDS: + outp->dcb->type = DCB_OUTPUT_TMDS; + outp->dcb->duallink_possible = outp->outp.info.tmds.dual; + break; + case NVIF_OUTP_LVDS: + outp->dcb->type = DCB_OUTPUT_LVDS; + outp->dcb->lvdsconf.use_acpi_for_edid = outp->outp.info.lvds.acpi_edid; + break; + case NVIF_OUTP_DP: + outp->dcb->type = DCB_OUTPUT_DP; + outp->dcb->dpconf.link_nr = outp->outp.info.dp.link_nr; + outp->dcb->dpconf.link_bw = outp->outp.info.dp.link_bw; + if (outp->outp.info.dp.mst) + has_mst = true; + break; + default: + WARN_ON(1); + continue; + } + + outp->dcb->heads = outp->outp.info.heads; + outp->dcb->connector = outp->outp.info.conn; + outp->dcb->i2c_index = outp->outp.info.ddc; + + switch (outp->outp.info.type) { + case NVIF_OUTP_DAC : ret = nv50_dac_create(outp); break; + case NVIF_OUTP_SOR : ret = nv50_sor_create(outp); break; + case NVIF_OUTP_PIOR: ret = nv50_pior_create(outp); break; + default: + WARN_ON(1); + continue; } if (ret) { NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", - dcbe->location, dcbe->type, - ffs(dcbe->or) - 1, ret); - ret = 0; + i, outp->outp.info.type, outp->outp.info.proto, ret); } } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index 1e5601223c753..5508a7cfd4924 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -108,8 +108,6 @@ void nv50_dmac_destroy(struct nv50_dmac *); */ struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder); -bool nv50_has_mst(struct nouveau_drm *drm); - u32 *evo_wait(struct nv50_dmac *, int nr); void evo_kick(u32 *, struct nv50_dmac *); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 502f342e0d775..bde9bfae8d11f 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -8,7 +8,36 @@ union nvif_outp_args { struct nvif_outp_v0 { __u8 version; __u8 id; /* DCB device index. */ - __u8 pad02[6]; +#define NVIF_OUTP_V0_TYPE_DAC 0x00 +#define NVIF_OUTP_V0_TYPE_SOR 0x01 +#define NVIF_OUTP_V0_TYPE_PIOR 0x02 + __u8 type; +#define NVIF_OUTP_V0_PROTO_RGB_CRT 0x00 +#define NVIF_OUTP_V0_PROTO_TMDS 0x01 +#define NVIF_OUTP_V0_PROTO_LVDS 0x02 +#define NVIF_OUTP_V0_PROTO_DP 0x03 + __u8 proto; + __u8 heads; + __u8 ddc; + __u8 conn; + union { + struct { + __u32 freq_max; + } rgb_crt; + struct { + __u8 dual; + } tmds; + struct { + __u8 acpi_edid; + } lvds; + struct { + __u8 aux; + __u8 mst; + __u8 increased_wm; + __u8 link_nr; + __u32 link_bw; + } dp; + }; } v0; }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 2d86838ed5598..bc122a5ba7df7 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -8,6 +8,46 @@ struct nvif_disp; struct nvif_outp { struct nvif_object object; + u32 id; + + struct { + enum { + NVIF_OUTP_DAC, + NVIF_OUTP_SOR, + NVIF_OUTP_PIOR, + } type; + + enum { + NVIF_OUTP_RGB_CRT, + NVIF_OUTP_TMDS, + NVIF_OUTP_LVDS, + NVIF_OUTP_DP, + } proto; + + u8 heads; +#define NVIF_OUTP_DDC_INVALID 0xff + u8 ddc; + u8 conn; + + union { + struct { + u32 freq_max; + } rgb_crt; + struct { + bool dual; + } tmds; + struct { + bool acpi_edid; + } lvds; + struct { + u8 aux; + bool mst; + bool increased_wm; + u8 link_nr; + u32 link_bw; + } dp; + }; + } info; struct { int id; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 21cc8dfcb7add..94498c15b50e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1135,7 +1135,7 @@ nouveau_connector_atomic_check(struct drm_connector *connector, struct drm_atomi struct drm_connector_state *conn_state drm_atomic_get_new_connector_state(state, connector); - if (!nv_conn->dp_encoder || !nv50_has_mst(nouveau_drm(connector->dev))) + if (!nv_conn->dp_encoder || !nv_conn->dp_encoder->dp.mstm) return 0; return drm_dp_mst_root_conn_atomic_check(conn_state, &nv_conn->dp_encoder->dp.mstm->mgr); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 97e5855c2cf54..5d3190c05250a 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -511,6 +511,50 @@ nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_out if (ret) return ret; + outp->id = args.id; + + switch (args.type) { + case NVIF_OUTP_V0_TYPE_DAC : outp->info.type = NVIF_OUTP_DAC; break; + case NVIF_OUTP_V0_TYPE_SOR : outp->info.type = NVIF_OUTP_SOR; break; + case NVIF_OUTP_V0_TYPE_PIOR: outp->info.type = NVIF_OUTP_PIOR; break; + break; + default: + WARN_ON(1); + nvif_outp_dtor(outp); + return -EINVAL; + } + + switch (args.proto) { + case NVIF_OUTP_V0_PROTO_RGB_CRT: + outp->info.proto = NVIF_OUTP_RGB_CRT; + outp->info.rgb_crt.freq_max = args.rgb_crt.freq_max; + break; + case NVIF_OUTP_V0_PROTO_TMDS: + outp->info.proto = NVIF_OUTP_TMDS; + outp->info.tmds.dual = args.tmds.dual; + break; + case NVIF_OUTP_V0_PROTO_LVDS: + outp->info.proto = NVIF_OUTP_LVDS; + outp->info.lvds.acpi_edid = args.lvds.acpi_edid; + break; + case NVIF_OUTP_V0_PROTO_DP: + outp->info.proto = NVIF_OUTP_DP; + outp->info.dp.aux = args.dp.aux; + outp->info.dp.mst = args.dp.mst; + outp->info.dp.increased_wm = args.dp.increased_wm; + outp->info.dp.link_nr = args.dp.link_nr; + outp->info.dp.link_bw = args.dp.link_bw; + break; + default: + WARN_ON(1); + nvif_outp_dtor(outp); + return -EINVAL; + } + + outp->info.heads = args.heads; + outp->info.ddc = args.ddc; + outp->info.conn = args.conn; + outp->or.id = -1; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index b35fae96d855d..a109348bd63b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -639,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; @@ -667,6 +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); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 3ec7318d9144e..ebd2f499b4b1d 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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index ad52d9ed594af..e4279f1772a1b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -606,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; } -- 2.41.0
Lyude Paul
2023-Sep-19 21:56 UTC
[Nouveau] [PATCH v3 44/44] drm/nouveau/kms/nv50-: disable dcb parsing
From: Ben Skeggs <bskeggs at redhat.com> - nvkm should provide all this info now - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs at redhat.com> Reviewed-by: Lyude Paul <lyude at redhat.com> Acked-by: Danilo Krummrich <me at dakr.org> Signed-off-by: Lyude Paul <lyude at redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 8 +++++--- drivers/gpu/drm/nouveau/nouveau_display.c | 8 ++++---- drivers/gpu/drm/nouveau/nvif/disp.c | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 189903b65edc9..9e878cdc8e38e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2093,9 +2093,11 @@ nouveau_bios_init(struct drm_device *dev) if (!NVInitVBIOS(dev)) return -ENODEV; - ret = parse_dcb_table(dev, bios); - if (ret) - return ret; + if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) { + ret = parse_dcb_table(dev, bios); + if (ret) + return ret; + } if (!bios->major_version) /* we don't run version 0 bios */ return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 99977e5fe7161..d8c92521226d9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -724,10 +724,10 @@ nouveau_display_create(struct drm_device *dev) drm_kms_helper_poll_init(dev); drm_kms_helper_poll_disable(dev); - if (nouveau_modeset != 2 && drm->vbios.dcb.entries) { - ret = nvif_disp_ctor(&drm->client.device, "kmsDisp", 0, - &disp->disp); - if (ret == 0) { + if (nouveau_modeset != 2) { + ret = nvif_disp_ctor(&drm->client.device, "kmsDisp", 0, &disp->disp); + + if (!ret && (disp->disp.outp_mask || drm->vbios.dcb.entries)) { nouveau_display_create_properties(dev); if (disp->disp.object.oclass < NV50_DISP) { dev->mode_config.fb_modifiers_not_supported = true; diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c index 09915f2715afd..097246e10cdb7 100644 --- a/drivers/gpu/drm/nouveau/nvif/disp.c +++ b/drivers/gpu/drm/nouveau/nvif/disp.c @@ -60,7 +60,7 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct cid = nvif_sclass(&device->object, disps, oclass); disp->object.client = NULL; if (cid < 0) { - NVIF_ERRON(cid, &device->object, "[NEW disp%04x] not supported", oclass); + NVIF_DEBUG(&device->object, "[NEW disp%04x] not supported", oclass); return cid; } -- 2.41.0
Timur Tabi
2023-Sep-20 21:42 UTC
[Nouveau] [PATCH v3 00/44] drm/nouveau: initial support for GSP-RM 535.54.04 (and Ada GPUs)
On Tue, 2023-09-19 at 17:55 -0400, Lyude Paul wrote:> Hey everyone! I'm just going through and rebasing Ben's display patches > so I can push them in just a moment :). > > (*the rest of this email can be read in Ben Skegg's voice*) > > The primary issue being tackled here is that, for historical reasons (we > didn't know any better / couldn't make it work reliably otherwise), some > operations (SOR routing, DP link training) were performed during the 2nd > HW supervisor interrupt.I understand very little about Nouveau internals (or DRM drivers), so I can't do a thorough review, but I did look over the patches and provided some feedback. So, for what it's worth, Reviewed-by: Timur Tabi <ttabi at nvidia.com>